summaryrefslogtreecommitdiffstats
path: root/accessible/windows
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /accessible/windows
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'accessible/windows')
-rw-r--r--accessible/windows/ProxyWrappers.h92
-rw-r--r--accessible/windows/ia2/ia2Accessible.cpp810
-rw-r--r--accessible/windows/ia2/ia2Accessible.h122
-rw-r--r--accessible/windows/ia2/ia2AccessibleAction.cpp188
-rw-r--r--accessible/windows/ia2/ia2AccessibleAction.h93
-rw-r--r--accessible/windows/ia2/ia2AccessibleComponent.cpp127
-rw-r--r--accessible/windows/ia2/ia2AccessibleComponent.h38
-rw-r--r--accessible/windows/ia2/ia2AccessibleEditableText.cpp153
-rw-r--r--accessible/windows/ia2/ia2AccessibleEditableText.h56
-rw-r--r--accessible/windows/ia2/ia2AccessibleHyperlink.cpp205
-rw-r--r--accessible/windows/ia2/ia2AccessibleHyperlink.h51
-rw-r--r--accessible/windows/ia2/ia2AccessibleHypertext.cpp93
-rw-r--r--accessible/windows/ia2/ia2AccessibleHypertext.h43
-rw-r--r--accessible/windows/ia2/ia2AccessibleImage.cpp119
-rw-r--r--accessible/windows/ia2/ia2AccessibleImage.h40
-rw-r--r--accessible/windows/ia2/ia2AccessibleRelation.cpp125
-rw-r--r--accessible/windows/ia2/ia2AccessibleRelation.h85
-rw-r--r--accessible/windows/ia2/ia2AccessibleTable.cpp747
-rw-r--r--accessible/windows/ia2/ia2AccessibleTable.h176
-rw-r--r--accessible/windows/ia2/ia2AccessibleTableCell.cpp257
-rw-r--r--accessible/windows/ia2/ia2AccessibleTableCell.h69
-rw-r--r--accessible/windows/ia2/ia2AccessibleText.cpp598
-rw-r--r--accessible/windows/ia2/ia2AccessibleText.h275
-rw-r--r--accessible/windows/ia2/ia2AccessibleValue.cpp151
-rw-r--r--accessible/windows/ia2/ia2AccessibleValue.h41
-rw-r--r--accessible/windows/ia2/moz.build58
-rw-r--r--accessible/windows/moz.build8
-rw-r--r--accessible/windows/msaa/ARIAGridAccessibleWrap.cpp47
-rw-r--r--accessible/windows/msaa/ARIAGridAccessibleWrap.h65
-rw-r--r--accessible/windows/msaa/AccessibleWrap.cpp1686
-rw-r--r--accessible/windows/msaa/AccessibleWrap.h265
-rw-r--r--accessible/windows/msaa/ApplicationAccessibleWrap.cpp162
-rw-r--r--accessible/windows/msaa/ApplicationAccessibleWrap.h52
-rw-r--r--accessible/windows/msaa/Compatibility.cpp112
-rw-r--r--accessible/windows/msaa/Compatibility.h79
-rw-r--r--accessible/windows/msaa/DocAccessibleWrap.cpp165
-rw-r--r--accessible/windows/msaa/DocAccessibleWrap.h65
-rw-r--r--accessible/windows/msaa/EnumVariant.cpp108
-rw-r--r--accessible/windows/msaa/EnumVariant.h60
-rw-r--r--accessible/windows/msaa/HTMLTableAccessibleWrap.cpp64
-rw-r--r--accessible/windows/msaa/HTMLTableAccessibleWrap.h93
-rw-r--r--accessible/windows/msaa/HTMLWin32ObjectAccessible.cpp109
-rw-r--r--accessible/windows/msaa/HTMLWin32ObjectAccessible.h70
-rw-r--r--accessible/windows/msaa/HyperTextAccessibleWrap.cpp67
-rw-r--r--accessible/windows/msaa/HyperTextAccessibleWrap.h46
-rw-r--r--accessible/windows/msaa/IDSet.h136
-rw-r--r--accessible/windows/msaa/IUnknownImpl.cpp58
-rw-r--r--accessible/windows/msaa/IUnknownImpl.h192
-rw-r--r--accessible/windows/msaa/ImageAccessibleWrap.cpp20
-rw-r--r--accessible/windows/msaa/ImageAccessibleWrap.h38
-rw-r--r--accessible/windows/msaa/MsaaIdGenerator.cpp243
-rw-r--r--accessible/windows/msaa/MsaaIdGenerator.h56
-rw-r--r--accessible/windows/msaa/Platform.cpp147
-rw-r--r--accessible/windows/msaa/RootAccessibleWrap.cpp45
-rw-r--r--accessible/windows/msaa/RootAccessibleWrap.h27
-rw-r--r--accessible/windows/msaa/ServiceProvider.cpp96
-rw-r--r--accessible/windows/msaa/ServiceProvider.h38
-rw-r--r--accessible/windows/msaa/TextLeafAccessibleWrap.cpp21
-rw-r--r--accessible/windows/msaa/TextLeafAccessibleWrap.h33
-rw-r--r--accessible/windows/msaa/XULListboxAccessibleWrap.cpp46
-rw-r--r--accessible/windows/msaa/XULListboxAccessibleWrap.h64
-rw-r--r--accessible/windows/msaa/XULMenuAccessibleWrap.cpp36
-rw-r--r--accessible/windows/msaa/XULMenuAccessibleWrap.h27
-rw-r--r--accessible/windows/msaa/XULTreeGridAccessibleWrap.cpp44
-rw-r--r--accessible/windows/msaa/XULTreeGridAccessibleWrap.h71
-rw-r--r--accessible/windows/msaa/moz.build76
-rw-r--r--accessible/windows/msaa/nsEventMap.h103
-rw-r--r--accessible/windows/msaa/nsWinUtils.cpp181
-rw-r--r--accessible/windows/msaa/nsWinUtils.h86
-rw-r--r--accessible/windows/sdn/moz.build24
-rw-r--r--accessible/windows/sdn/sdnAccessible-inl.h34
-rw-r--r--accessible/windows/sdn/sdnAccessible.cpp539
-rw-r--r--accessible/windows/sdn/sdnAccessible.h119
-rw-r--r--accessible/windows/sdn/sdnDocAccessible.cpp157
-rw-r--r--accessible/windows/sdn/sdnDocAccessible.h53
-rw-r--r--accessible/windows/sdn/sdnTextAccessible.cpp210
-rw-r--r--accessible/windows/sdn/sdnTextAccessible.h71
-rw-r--r--accessible/windows/uia/moz.build22
-rw-r--r--accessible/windows/uia/uiaRawElmProvider.cpp246
-rw-r--r--accessible/windows/uia/uiaRawElmProvider.h75
80 files changed, 11569 insertions, 0 deletions
diff --git a/accessible/windows/ProxyWrappers.h b/accessible/windows/ProxyWrappers.h
new file mode 100644
index 000000000..6e7c84e18
--- /dev/null
+++ b/accessible/windows/ProxyWrappers.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. *
+ */
+
+#ifndef MOZILLA_A11Y_ProxyWrappers_h
+#define MOZILLA_A11Y_ProxyWrappers_h
+
+#include "HyperTextAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ProxyAccessibleWrap : public AccessibleWrap
+{
+public:
+ ProxyAccessibleWrap(ProxyAccessible* aProxy) :
+ AccessibleWrap(nullptr, nullptr)
+ {
+ mType = eProxyType;
+ mBits.proxy = aProxy;
+ }
+
+ virtual void Shutdown() override
+ {
+ mBits.proxy = nullptr;
+ mStateFlags |= eIsDefunct;
+ }
+
+ virtual void GetNativeInterface(void** aOutAccessible) override
+ {
+ mBits.proxy->GetCOMInterface(aOutAccessible);
+ }
+};
+
+class HyperTextProxyAccessibleWrap : public HyperTextAccessibleWrap
+{
+public:
+ HyperTextProxyAccessibleWrap(ProxyAccessible* aProxy) :
+ HyperTextAccessibleWrap(nullptr, nullptr)
+ {
+ mType = eProxyType;
+ mBits.proxy = aProxy;
+ }
+
+ virtual void Shutdown() override
+ {
+ mBits.proxy = nullptr;
+ mStateFlags |= eIsDefunct;
+ }
+
+ virtual void GetNativeInterface(void** aOutAccessible) override
+ {
+ mBits.proxy->GetCOMInterface(aOutAccessible);
+ }
+};
+
+class DocProxyAccessibleWrap : public HyperTextProxyAccessibleWrap
+{
+public:
+ DocProxyAccessibleWrap(ProxyAccessible* aProxy) :
+ HyperTextProxyAccessibleWrap(aProxy)
+ { mGenericTypes |= eDocument; }
+
+ void AddID(uint32_t aID, AccessibleWrap* aAcc)
+ { mIDToAccessibleMap.Put(aID, aAcc); }
+ void RemoveID(uint32_t aID) { mIDToAccessibleMap.Remove(aID); }
+ AccessibleWrap* GetAccessibleByID(uint32_t aID) const
+ { return mIDToAccessibleMap.Get(aID); }
+
+private:
+ /*
+ * This provides a mapping from 32 bit id to accessible objects.
+ */
+ nsDataHashtable<nsUint32HashKey, AccessibleWrap*> mIDToAccessibleMap;
+};
+
+template<typename T>
+inline ProxyAccessible*
+HyperTextProxyFor(T* aWrapper)
+{
+ static_assert(mozilla::IsBaseOf<IUnknown, T>::value, "only IAccessible* should be passed in");
+ auto wrapper = static_cast<HyperTextProxyAccessibleWrap*>(aWrapper);
+ return wrapper->IsProxy() ? wrapper->Proxy() : nullptr;
+}
+
+}
+}
+
+#endif
diff --git a/accessible/windows/ia2/ia2Accessible.cpp b/accessible/windows/ia2/ia2Accessible.cpp
new file mode 100644
index 000000000..c72719b51
--- /dev/null
+++ b/accessible/windows/ia2/ia2Accessible.cpp
@@ -0,0 +1,810 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AccessibleWrap.h"
+
+#include "Accessible2_i.c"
+#include "Accessible2_2_i.c"
+#include "Accessible2_3_i.c"
+#include "AccessibleRole.h"
+#include "AccessibleStates.h"
+
+#include "Compatibility.h"
+#include "ia2AccessibleRelation.h"
+#include "IUnknownImpl.h"
+#include "nsCoreUtils.h"
+#include "nsIAccessibleTypes.h"
+#include "mozilla/a11y/PDocAccessible.h"
+#include "Relation.h"
+#include "TextRange-inl.h"
+#include "nsAccessibilityService.h"
+
+#include "nsIPersistentProperties2.h"
+#include "nsISimpleEnumerator.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+template<typename String> static void EscapeAttributeChars(String& aStr);
+
+////////////////////////////////////////////////////////////////////////////////
+// ia2Accessible
+////////////////////////////////////////////////////////////////////////////////
+
+STDMETHODIMP
+ia2Accessible::QueryInterface(REFIID iid, void** ppv)
+{
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessible2_3 == iid)
+ *ppv = static_cast<IAccessible2_3*>(this);
+ else if (IID_IAccessible2_2 == iid)
+ *ppv = static_cast<IAccessible2_2*>(this);
+ else if (IID_IAccessible2 == iid && !Compatibility::IsIA2Off())
+ *ppv = static_cast<IAccessible2*>(this);
+
+ if (*ppv) {
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessible2
+
+STDMETHODIMP
+ia2Accessible::get_nRelations(long* aNRelations)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNRelations)
+ return E_INVALIDARG;
+ *aNRelations = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ MOZ_ASSERT(!acc->IsProxy());
+
+ for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
+ if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
+ continue;
+
+ Relation rel = acc->RelationByType(sRelationTypePairs[idx].first);
+ if (rel.Next())
+ (*aNRelations)++;
+ }
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_relation(long aRelationIndex,
+ IAccessibleRelation** aRelation)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRelation || aRelationIndex < 0)
+ return E_INVALIDARG;
+ *aRelation = nullptr;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ MOZ_ASSERT(!acc->IsProxy());
+
+ long relIdx = 0;
+ for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
+ if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
+ continue;
+
+ RelationType relationType = sRelationTypePairs[idx].first;
+ Relation rel = acc->RelationByType(relationType);
+ RefPtr<ia2AccessibleRelation> ia2Relation =
+ new ia2AccessibleRelation(relationType, &rel);
+ if (ia2Relation->HasTargets()) {
+ if (relIdx == aRelationIndex) {
+ ia2Relation.forget(aRelation);
+ return S_OK;
+ }
+
+ relIdx++;
+ }
+ }
+
+ return E_INVALIDARG;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_relations(long aMaxRelations,
+ IAccessibleRelation** aRelation,
+ long *aNRelations)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRelation || !aNRelations || aMaxRelations <= 0)
+ return E_INVALIDARG;
+ *aNRelations = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ MOZ_ASSERT(!acc->IsProxy());
+
+ for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs) &&
+ *aNRelations < aMaxRelations; idx++) {
+ if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
+ continue;
+
+ RelationType relationType = sRelationTypePairs[idx].first;
+ Relation rel = acc->RelationByType(relationType);
+ RefPtr<ia2AccessibleRelation> ia2Rel =
+ new ia2AccessibleRelation(relationType, &rel);
+ if (ia2Rel->HasTargets()) {
+ ia2Rel.forget(aRelation + (*aNRelations));
+ (*aNRelations)++;
+ }
+ }
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::role(long* aRole)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRole)
+ return E_INVALIDARG;
+ *aRole = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+#define ROLE(_geckoRole, stringRole, atkRole, macRole, \
+ msaaRole, ia2Role, nameRule) \
+ case roles::_geckoRole: \
+ *aRole = ia2Role; \
+ break;
+
+ a11y::role geckoRole;
+ MOZ_ASSERT(!acc->IsProxy());
+ geckoRole = acc->Role();
+ switch (geckoRole) {
+#include "RoleMap.h"
+ default:
+ MOZ_CRASH("Unknown role.");
+ }
+
+#undef ROLE
+
+ // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call
+ // the IA2 role a ROLE_OUTLINEITEM.
+ MOZ_ASSERT(!acc->IsProxy());
+ if (geckoRole == roles::ROW) {
+ Accessible* xpParent = acc->Parent();
+ if (xpParent && xpParent->Role() == roles::TREE_TABLE)
+ *aRole = ROLE_SYSTEM_OUTLINEITEM;
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::scrollTo(enum IA2ScrollType aScrollType)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ MOZ_ASSERT(!acc->IsProxy());
+ nsCoreUtils::ScrollTo(acc->Document()->PresShell(), acc->GetContent(),
+ aScrollType);
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::scrollToPoint(enum IA2CoordinateType aCoordType,
+ long aX, long aY)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
+ nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
+ nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+
+ MOZ_ASSERT(!acc->IsProxy());
+ acc->ScrollToPoint(geckoCoordType, aX, aY);
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_groupPosition(long* aGroupLevel,
+ long* aSimilarItemsInGroup,
+ long* aPositionInGroup)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup)
+ return E_INVALIDARG;
+
+ *aGroupLevel = 0;
+ *aSimilarItemsInGroup = 0;
+ *aPositionInGroup = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ GroupPos groupPos = acc->GroupPosition();
+
+ // Group information for accessibles having level only (like html headings
+ // elements) isn't exposed by this method. AT should look for 'level' object
+ // attribute.
+ if (!groupPos.setSize && !groupPos.posInSet)
+ return S_FALSE;
+
+ *aGroupLevel = groupPos.level;
+ *aSimilarItemsInGroup = groupPos.setSize;
+ *aPositionInGroup = groupPos.posInSet;
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_states(AccessibleStates* aStates)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aStates)
+ return E_INVALIDARG;
+ *aStates = 0;
+
+ // XXX: bug 344674 should come with better approach that we have here.
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct()) {
+ *aStates = IA2_STATE_DEFUNCT;
+ return S_OK;
+ }
+
+ uint64_t state;
+ MOZ_ASSERT(!acc->IsProxy());
+ state = acc->State();
+
+ if (state & states::INVALID)
+ *aStates |= IA2_STATE_INVALID_ENTRY;
+ if (state & states::REQUIRED)
+ *aStates |= IA2_STATE_REQUIRED;
+
+ // The following IA2 states are not supported by Gecko
+ // IA2_STATE_ARMED
+ // IA2_STATE_MANAGES_DESCENDANTS
+ // IA2_STATE_ICONIFIED
+ // IA2_STATE_INVALID // This is not a state, it is the absence of a state
+
+ if (state & states::ACTIVE)
+ *aStates |= IA2_STATE_ACTIVE;
+ if (state & states::DEFUNCT)
+ *aStates |= IA2_STATE_DEFUNCT;
+ if (state & states::EDITABLE)
+ *aStates |= IA2_STATE_EDITABLE;
+ if (state & states::HORIZONTAL)
+ *aStates |= IA2_STATE_HORIZONTAL;
+ if (state & states::MODAL)
+ *aStates |= IA2_STATE_MODAL;
+ if (state & states::MULTI_LINE)
+ *aStates |= IA2_STATE_MULTI_LINE;
+ if (state & states::OPAQUE1)
+ *aStates |= IA2_STATE_OPAQUE;
+ if (state & states::SELECTABLE_TEXT)
+ *aStates |= IA2_STATE_SELECTABLE_TEXT;
+ if (state & states::SINGLE_LINE)
+ *aStates |= IA2_STATE_SINGLE_LINE;
+ if (state & states::STALE)
+ *aStates |= IA2_STATE_STALE;
+ if (state & states::SUPPORTS_AUTOCOMPLETION)
+ *aStates |= IA2_STATE_SUPPORTS_AUTOCOMPLETION;
+ if (state & states::TRANSIENT)
+ *aStates |= IA2_STATE_TRANSIENT;
+ if (state & states::VERTICAL)
+ *aStates |= IA2_STATE_VERTICAL;
+ if (state & states::CHECKED)
+ *aStates |= IA2_STATE_CHECKABLE;
+ if (state & states::PINNED)
+ *aStates |= IA2_STATE_PINNED;
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_extendedRole(BSTR* aExtendedRole)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aExtendedRole)
+ return E_INVALIDARG;
+
+ *aExtendedRole = nullptr;
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_localizedExtendedRole(BSTR* aLocalizedExtendedRole)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aLocalizedExtendedRole)
+ return E_INVALIDARG;
+
+ *aLocalizedExtendedRole = nullptr;
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_nExtendedStates(long* aNExtendedStates)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNExtendedStates)
+ return E_INVALIDARG;
+
+ *aNExtendedStates = 0;
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_extendedStates(long aMaxExtendedStates,
+ BSTR** aExtendedStates,
+ long* aNExtendedStates)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aExtendedStates || !aNExtendedStates)
+ return E_INVALIDARG;
+
+ *aExtendedStates = nullptr;
+ *aNExtendedStates = 0;
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_localizedExtendedStates(long aMaxLocalizedExtendedStates,
+ BSTR** aLocalizedExtendedStates,
+ long* aNLocalizedExtendedStates)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aLocalizedExtendedStates || !aNLocalizedExtendedStates)
+ return E_INVALIDARG;
+
+ *aLocalizedExtendedStates = nullptr;
+ *aNLocalizedExtendedStates = 0;
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_uniqueID(long* aUniqueID)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aUniqueID)
+ return E_INVALIDARG;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ *aUniqueID = AccessibleWrap::GetChildIDFor(acc);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_windowHandle(HWND* aWindowHandle)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aWindowHandle)
+ return E_INVALIDARG;
+ *aWindowHandle = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ *aWindowHandle = AccessibleWrap::GetHWNDFor(acc);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_indexInParent(long* aIndexInParent)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aIndexInParent)
+ return E_INVALIDARG;
+ *aIndexInParent = -1;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ MOZ_ASSERT(!acc->IsProxy());
+ *aIndexInParent = acc->IndexInParent();
+
+ if (*aIndexInParent == -1)
+ return S_FALSE;
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_locale(IA2Locale* aLocale)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aLocale)
+ return E_INVALIDARG;
+
+ // Language codes consist of a primary code and a possibly empty series of
+ // subcodes: language-code = primary-code ( "-" subcode )*
+ // Two-letter primary codes are reserved for [ISO639] language abbreviations.
+ // Any two-letter subcode is understood to be a [ISO3166] country code.
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString lang;
+ acc->Language(lang);
+
+ // If primary code consists from two letters then expose it as language.
+ int32_t offset = lang.FindChar('-', 0);
+ if (offset == -1) {
+ if (lang.Length() == 2) {
+ aLocale->language = ::SysAllocString(lang.get());
+ return S_OK;
+ }
+ } else if (offset == 2) {
+ aLocale->language = ::SysAllocStringLen(lang.get(), 2);
+
+ // If the first subcode consists from two letters then expose it as
+ // country.
+ offset = lang.FindChar('-', 3);
+ if (offset == -1) {
+ if (lang.Length() == 5) {
+ aLocale->country = ::SysAllocString(lang.get() + 3);
+ return S_OK;
+ }
+ } else if (offset == 5) {
+ aLocale->country = ::SysAllocStringLen(lang.get() + 3, 2);
+ }
+ }
+
+ // Expose as a string if primary code or subcode cannot point to language or
+ // country abbreviations or if there are more than one subcode.
+ aLocale->variant = ::SysAllocString(lang.get());
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_attributes(BSTR* aAttributes)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAttributes)
+ return E_INVALIDARG;
+ *aAttributes = nullptr;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ // The format is name:value;name:value; with \ for escaping these
+ // characters ":;=,\".
+ if (!acc->IsProxy()) {
+ nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes();
+ return ConvertToIA2Attributes(attributes, aAttributes);
+ }
+
+ MOZ_ASSERT(!acc->IsProxy());
+ return E_UNEXPECTED;
+
+ A11Y_TRYBLOCK_END
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessible2_2
+
+STDMETHODIMP
+ia2Accessible::get_attribute(BSTR name, VARIANT* aAttribute)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAttribute)
+ return E_INVALIDARG;
+
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible,
+ long* aCaretOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAccessible || !aCaretOffset)
+ return E_INVALIDARG;
+
+ *aAccessible = nullptr;
+ *aCaretOffset = -1;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ int32_t caretOffset = -1;
+ Accessible* accWithCaret = SelectionMgr()->AccessibleWithCaret(&caretOffset);
+ if (acc->Document() != accWithCaret->Document())
+ return S_FALSE;
+
+ Accessible* child = accWithCaret;
+ while (!child->IsDoc() && child != acc)
+ child = child->Parent();
+
+ if (child != acc)
+ return S_FALSE;
+
+ *aAccessible = static_cast<IAccessible2*>(
+ static_cast<AccessibleWrap*>(accWithCaret));
+ (*aAccessible)->AddRef();
+ *aCaretOffset = caretOffset;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_relationTargetsOfType(BSTR aType,
+ long aMaxTargets,
+ IUnknown*** aTargets,
+ long* aNTargets)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aTargets || !aNTargets || aMaxTargets < 0)
+ return E_INVALIDARG;
+ *aNTargets = 0;
+
+ Maybe<RelationType> relationType;
+ for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
+ if (wcscmp(aType, sRelationTypePairs[idx].second) == 0) {
+ relationType.emplace(sRelationTypePairs[idx].first);
+ break;
+ }
+ }
+ if (!relationType)
+ return E_INVALIDARG;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsTArray<Accessible*> targets;
+ MOZ_ASSERT(!acc->IsProxy());
+ Relation rel = acc->RelationByType(*relationType);
+ Accessible* target = nullptr;
+ while ((target = rel.Next()) &&
+ static_cast<long>(targets.Length()) <= aMaxTargets) {
+ targets.AppendElement(target);
+ }
+
+ *aNTargets = targets.Length();
+ *aTargets = static_cast<IUnknown**>(
+ ::CoTaskMemAlloc(sizeof(IUnknown*) * *aNTargets));
+ if (!*aTargets)
+ return E_OUTOFMEMORY;
+
+ for (int32_t i = 0; i < *aNTargets; i++) {
+ AccessibleWrap* target= static_cast<AccessibleWrap*>(targets[i]);
+ (*aTargets)[i] = static_cast<IAccessible2*>(target);
+ (*aTargets)[i]->AddRef();
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2Accessible::get_selectionRanges(IA2Range** aRanges,
+ long *aNRanges)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRanges || !aNRanges)
+ return E_INVALIDARG;
+
+ *aNRanges = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<TextRange, 1> ranges;
+ acc->Document()->SelectionRanges(&ranges);
+ uint32_t len = ranges.Length();
+ for (uint32_t idx = 0; idx < len; idx++) {
+ if (!ranges[idx].Crop(acc)) {
+ ranges.RemoveElementAt(idx);
+ }
+ }
+
+ *aNRanges = ranges.Length();
+ *aRanges = static_cast<IA2Range*>(
+ ::CoTaskMemAlloc(sizeof(IA2Range) * *aNRanges));
+ if (!*aRanges)
+ return E_OUTOFMEMORY;
+
+ for (uint32_t idx = 0; idx < static_cast<uint32_t>(*aNRanges); idx++) {
+ AccessibleWrap* anchor =
+ static_cast<AccessibleWrap*>(ranges[idx].StartContainer());
+ (*aRanges)[idx].anchor = static_cast<IAccessible2*>(anchor);
+ anchor->AddRef();
+
+ (*aRanges)[idx].anchorOffset = ranges[idx].StartOffset();
+
+ AccessibleWrap* active =
+ static_cast<AccessibleWrap*>(ranges[idx].EndContainer());
+ (*aRanges)[idx].active = static_cast<IAccessible2*>(active);
+ active->AddRef();
+
+ (*aRanges)[idx].activeOffset = ranges[idx].EndOffset();
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+template<typename String>
+static inline void
+EscapeAttributeChars(String& aStr)
+{
+ int32_t offset = 0;
+ static const char kCharsToEscape[] = ":;=,\\";
+ while ((offset = aStr.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
+ aStr.Insert('\\', offset);
+ offset += 2;
+ }
+}
+
+HRESULT
+ia2Accessible::ConvertToIA2Attributes(nsTArray<Attribute>* aAttributes,
+ BSTR* aIA2Attributes)
+{
+ nsString attrStr;
+ size_t attrCount = aAttributes->Length();
+ for (size_t i = 0; i < attrCount; i++) {
+ EscapeAttributeChars(aAttributes->ElementAt(i).Name());
+ EscapeAttributeChars(aAttributes->ElementAt(i).Value());
+ AppendUTF8toUTF16(aAttributes->ElementAt(i).Name(), attrStr);
+ attrStr.Append(':');
+ attrStr.Append(aAttributes->ElementAt(i).Value());
+ attrStr.Append(';');
+ }
+
+ if (attrStr.IsEmpty())
+ return S_FALSE;
+
+ *aIA2Attributes = ::SysAllocStringLen(attrStr.get(), attrStr.Length());
+ return *aIA2Attributes ? S_OK : E_OUTOFMEMORY;
+}
+
+HRESULT
+ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
+ BSTR* aIA2Attributes)
+{
+ *aIA2Attributes = nullptr;
+
+ // The format is name:value;name:value; with \ for escaping these
+ // characters ":;=,\".
+
+ if (!aAttributes)
+ return S_FALSE;
+
+ nsCOMPtr<nsISimpleEnumerator> propEnum;
+ aAttributes->Enumerate(getter_AddRefs(propEnum));
+ if (!propEnum)
+ return E_FAIL;
+
+ nsAutoString strAttrs;
+
+ bool hasMore = false;
+ while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsISupports> propSupports;
+ propEnum->GetNext(getter_AddRefs(propSupports));
+
+ nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(propSupports));
+ if (!propElem)
+ return E_FAIL;
+
+ nsAutoCString name;
+ if (NS_FAILED(propElem->GetKey(name)))
+ return E_FAIL;
+
+ EscapeAttributeChars(name);
+
+ nsAutoString value;
+ if (NS_FAILED(propElem->GetValue(value)))
+ return E_FAIL;
+
+ EscapeAttributeChars(value);
+
+ AppendUTF8toUTF16(name, strAttrs);
+ strAttrs.Append(':');
+ strAttrs.Append(value);
+ strAttrs.Append(';');
+ }
+
+ if (strAttrs.IsEmpty())
+ return S_FALSE;
+
+ *aIA2Attributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length());
+ return *aIA2Attributes ? S_OK : E_OUTOFMEMORY;
+}
diff --git a/accessible/windows/ia2/ia2Accessible.h b/accessible/windows/ia2/ia2Accessible.h
new file mode 100644
index 000000000..98ca4339b
--- /dev/null
+++ b/accessible/windows/ia2/ia2Accessible.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_ia2Accessible_h_
+#define mozilla_a11y_ia2Accessible_h_
+
+#include "nsISupports.h"
+
+#include "Accessible2_3.h"
+
+namespace mozilla {
+namespace a11y {
+class Attribute;
+
+class ia2Accessible : public IAccessible2_3
+{
+public:
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID, void**);
+
+ // IAccessible2
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nRelations(
+ /* [retval][out] */ long* nRelations);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relation(
+ /* [in] */ long relationIndex,
+ /* [retval][out] */ IAccessibleRelation** relation);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relations(
+ /* [in] */ long maxRelations,
+ /* [length_is][size_is][out] */ IAccessibleRelation** relation,
+ /* [retval][out] */ long* nRelations);
+
+ virtual HRESULT STDMETHODCALLTYPE role(
+ /* [retval][out] */ long* role);
+
+ virtual HRESULT STDMETHODCALLTYPE scrollTo(
+ /* [in] */ enum IA2ScrollType scrollType);
+
+ virtual HRESULT STDMETHODCALLTYPE scrollToPoint(
+ /* [in] */ enum IA2CoordinateType coordinateType,
+ /* [in] */ long x,
+ /* [in] */ long y);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_groupPosition(
+ /* [out] */ long* groupLevel,
+ /* [out] */ long* similarItemsInGroup,
+ /* [retval][out] */ long* positionInGroup);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_states(
+ /* [retval][out] */ AccessibleStates* states);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_extendedRole(
+ /* [retval][out] */ BSTR* extendedRole);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedExtendedRole(
+ /* [retval][out] */ BSTR* localizedExtendedRole);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nExtendedStates(
+ /* [retval][out] */ long* nExtendedStates);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_extendedStates(
+ /* [in] */ long maxExtendedStates,
+ /* [length_is][length_is][size_is][size_is][out] */ BSTR** extendedStates,
+ /* [retval][out] */ long* nExtendedStates);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedExtendedStates(
+ /* [in] */ long maxLocalizedExtendedStates,
+ /* [length_is][length_is][size_is][size_is][out] */ BSTR** localizedExtendedStates,
+ /* [retval][out] */ long* nLocalizedExtendedStates);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_uniqueID(
+ /* [retval][out] */ long* uniqueID);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_windowHandle(
+ /* [retval][out] */ HWND* windowHandle);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_indexInParent(
+ /* [retval][out] */ long* indexInParent);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_locale(
+ /* [retval][out] */ IA2Locale* locale);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_attributes(
+ /* [retval][out] */ BSTR* attributes);
+
+ // IAccessible2_2
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_attribute(
+ /* [in] */ BSTR name,
+ /* [out, retval] */ VARIANT* attribute);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_accessibleWithCaret(
+ /* [out] */ IUnknown** accessible,
+ /* [out, retval] */ long* caretOffset);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relationTargetsOfType(
+ /* [in] */ BSTR type,
+ /* [in] */ long maxTargets,
+ /* [out, size_is(,*nTargets)] */ IUnknown*** targets,
+ /* [out, retval] */ long* nTargets
+ );
+
+ // IAccessible2_3
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectionRanges(
+ /* [out, size_is(,*nRanges)] */ IA2Range** ranges,
+ /* [out, retval] */ long *nRanges);
+
+ // Helper method
+ static HRESULT ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
+ BSTR* aIA2Attributes);
+ static HRESULT ConvertToIA2Attributes(nsTArray<Attribute>* aAttributes,
+ BSTR* aIA2Attributes);
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleAction.cpp b/accessible/windows/ia2/ia2AccessibleAction.cpp
new file mode 100644
index 000000000..0710b753f
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleAction.cpp
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleAction.h"
+
+#include "AccessibleAction_i.c"
+
+#include "AccessibleWrap.h"
+#include "IUnknownImpl.h"
+
+using namespace mozilla::a11y;
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv)
+{
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleAction == iid &&
+ !static_cast<AccessibleWrap*>(this)->IsProxy()) {
+ *ppv = static_cast<IAccessibleAction*>(this);
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+// IAccessibleAction
+
+STDMETHODIMP
+ia2AccessibleAction::nActions(long* aActionCount)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aActionCount)
+ return E_INVALIDARG;
+
+ *aActionCount = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ *aActionCount = acc->ActionCount();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleAction::doAction(long aActionIndex)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ uint8_t index = static_cast<uint8_t>(aActionIndex);
+ return acc->DoAction(index) ? S_OK : E_INVALIDARG;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleAction::get_description(long aActionIndex, BSTR *aDescription)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aDescription)
+ return E_INVALIDARG;
+ *aDescription = nullptr;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString description;
+ uint8_t index = static_cast<uint8_t>(aActionIndex);
+ acc->ActionDescriptionAt(index, description);
+ if (description.IsEmpty())
+ return S_FALSE;
+
+ *aDescription = ::SysAllocStringLen(description.get(),
+ description.Length());
+ return *aDescription ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleAction::get_keyBinding(long aActionIndex, long aNumMaxBinding,
+ BSTR **aKeyBinding,
+ long *aNumBinding)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aKeyBinding)
+ return E_INVALIDARG;
+ *aKeyBinding = nullptr;
+
+ if (!aNumBinding)
+ return E_INVALIDARG;
+ *aNumBinding = 0;
+
+ if (aActionIndex != 0 || aNumMaxBinding < 1)
+ return E_INVALIDARG;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ // Expose keyboard shortcut if it's not exposed via MSAA keyboard shortcut.
+ KeyBinding keyBinding = acc->AccessKey();
+ if (keyBinding.IsEmpty())
+ return S_FALSE;
+
+ keyBinding = acc->KeyboardShortcut();
+ if (keyBinding.IsEmpty())
+ return S_FALSE;
+
+ nsAutoString keyStr;
+ keyBinding.ToString(keyStr);
+
+ *aKeyBinding = static_cast<BSTR*>(::CoTaskMemAlloc(sizeof(BSTR*)));
+ if (!*aKeyBinding)
+ return E_OUTOFMEMORY;
+
+ *(aKeyBinding[0]) = ::SysAllocStringLen(keyStr.get(), keyStr.Length());
+ if (!*(aKeyBinding[0])) {
+ ::CoTaskMemFree(*aKeyBinding);
+ return E_OUTOFMEMORY;
+ }
+
+ *aNumBinding = 1;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleAction::get_name(long aActionIndex, BSTR *aName)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aName)
+ return E_INVALIDARG;
+
+ *aName = nullptr;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString name;
+ uint8_t index = static_cast<uint8_t>(aActionIndex);
+ acc->ActionNameAt(index, name);
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ *aName = ::SysAllocStringLen(name.get(), name.Length());
+ return *aName ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleAction::get_localizedName(long aActionIndex, BSTR *aLocalizedName)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aLocalizedName)
+ return E_INVALIDARG;
+
+ *aLocalizedName = nullptr;
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
diff --git a/accessible/windows/ia2/ia2AccessibleAction.h b/accessible/windows/ia2/ia2AccessibleAction.h
new file mode 100644
index 000000000..6c978ff16
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleAction.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _ACCESSIBLE_ACTION_H
+#define _ACCESSIBLE_ACTION_H
+
+#include "nsISupports.h"
+
+#include "AccessibleAction.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ia2AccessibleAction: public IAccessibleAction
+{
+public:
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID, void**);
+
+ // IAccessibleAction
+ virtual HRESULT STDMETHODCALLTYPE nActions(
+ /* [retval][out] */ long *nActions);
+
+ virtual HRESULT STDMETHODCALLTYPE doAction(
+ /* [in] */ long actionIndex);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_description(
+ /* [in] */ long actionIndex,
+ /* [retval][out] */ BSTR *description);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_keyBinding(
+ /* [in] */ long actionIndex,
+ /* [in] */ long nMaxBinding,
+ /* [length_is][length_is][size_is][size_is][out] */ BSTR **keyBinding,
+ /* [retval][out] */ long *nBinding);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_name(
+ /* [in] */ long actionIndex,
+ /* [retval][out] */ BSTR *name);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedName(
+ /* [in] */ long actionIndex,
+ /* [retval][out] */ BSTR *localizedName);
+
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#define FORWARD_IACCESSIBLEACTION(Class) \
+virtual HRESULT STDMETHODCALLTYPE nActions(long *nActions) \
+{ \
+ return Class::nActions(nActions); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE doAction(long actionIndex) \
+{ \
+ return Class::doAction(actionIndex); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_description(long actionIndex, \
+ BSTR *description) \
+{ \
+ return Class::get_description(actionIndex, description); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_keyBinding(long actionIndex, \
+ long nMaxBinding, \
+ BSTR **keyBinding, \
+ long *nBinding) \
+{ \
+ return Class::get_keyBinding(actionIndex, nMaxBinding, keyBinding, nBinding);\
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_name(long actionIndex, BSTR *name) \
+{ \
+ return Class::get_name(actionIndex, name); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_localizedName(long actionIndex, \
+ BSTR *localizedName) \
+{ \
+ return Class::get_localizedName(actionIndex, localizedName); \
+} \
+ \
+
+#endif
+
diff --git a/accessible/windows/ia2/ia2AccessibleComponent.cpp b/accessible/windows/ia2/ia2AccessibleComponent.cpp
new file mode 100644
index 000000000..f32c09d1e
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleComponent.cpp
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleComponent.h"
+
+#include "AccessibleComponent_i.c"
+
+#include "AccessibleWrap.h"
+#include "States.h"
+#include "IUnknownImpl.h"
+
+#include "nsIFrame.h"
+
+using namespace mozilla::a11y;
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleComponent::QueryInterface(REFIID iid, void** ppv)
+{
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleComponent == iid) {
+ *ppv = static_cast<IAccessibleComponent*>(this);
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+// IAccessibleComponent
+
+STDMETHODIMP
+ia2AccessibleComponent::get_locationInParent(long* aX, long* aY)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aX || !aY)
+ return E_INVALIDARG;
+
+ *aX = 0;
+ *aY = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ // If the object is not on any screen the returned position is (0,0).
+ uint64_t state = acc->State();
+ if (state & states::INVISIBLE)
+ return S_OK;
+
+ nsIntRect rect = acc->Bounds();
+
+ // The coordinates of the returned position are relative to this object's
+ // parent or relative to the screen on which this object is rendered if it
+ // has no parent.
+ if (!acc->Parent()) {
+ *aX = rect.x;
+ *aY = rect.y;
+ return S_OK;
+ }
+
+ // The coordinates of the bounding box are given relative to the parent's
+ // coordinate system.
+ nsIntRect parentRect = acc->Parent()->Bounds();
+ *aX = rect.x - parentRect.x;
+ *aY = rect.y - parentRect.y;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleComponent::get_foreground(IA2Color* aForeground)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aForeground)
+ return E_INVALIDARG;
+
+ *aForeground = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsIFrame* frame = acc->GetFrame();
+ if (frame)
+ *aForeground = frame->StyleColor()->mColor;
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleComponent::get_background(IA2Color* aBackground)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aBackground)
+ return E_INVALIDARG;
+
+ *aBackground = 0;
+
+ AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsIFrame* frame = acc->GetFrame();
+ if (frame)
+ *aBackground = frame->StyleBackground()->mBackgroundColor;
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
diff --git a/accessible/windows/ia2/ia2AccessibleComponent.h b/accessible/windows/ia2/ia2AccessibleComponent.h
new file mode 100644
index 000000000..c14d7a113
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleComponent.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef IA2_ACCESSIBLE_COMPONENT_H_
+#define IA2_ACCESSIBLE_COMPONENT_H_
+
+#include "AccessibleComponent.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ia2AccessibleComponent : public IAccessibleComponent
+{
+public:
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID, void**);
+
+ // IAccessibleComponent
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_locationInParent(
+ /* [out] */ long *x,
+ /* [retval][out] */ long *y);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_foreground(
+ /* [retval][out] */ IA2Color *foreground);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_background(
+ /* [retval][out] */ IA2Color *background);
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleEditableText.cpp b/accessible/windows/ia2/ia2AccessibleEditableText.cpp
new file mode 100644
index 000000000..361d6a130
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleEditableText.cpp
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleEditableText.h"
+
+#include "AccessibleEditableText_i.c"
+#include "HyperTextAccessible-inl.h"
+#include "HyperTextAccessibleWrap.h"
+#include "ProxyWrappers.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+using namespace mozilla::a11y;
+
+// IAccessibleEditableText
+
+STDMETHODIMP
+ia2AccessibleEditableText::copyText(long aStartOffset, long aEndOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidRange(aStartOffset, aEndOffset))
+ return E_INVALIDARG;
+
+ textAcc->CopyText(aStartOffset, aEndOffset);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::deleteText(long aStartOffset, long aEndOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidRange(aStartOffset, aEndOffset))
+ return E_INVALIDARG;
+
+ textAcc->DeleteText(aStartOffset, aEndOffset);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::insertText(long aOffset, BSTR *aText)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ uint32_t length = ::SysStringLen(*aText);
+ nsAutoString text(*aText, length);
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidOffset(aOffset))
+ return E_INVALIDARG;
+
+ textAcc->InsertText(text, aOffset);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::cutText(long aStartOffset, long aEndOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidRange(aStartOffset, aEndOffset))
+ return E_INVALIDARG;
+
+ textAcc->CutText(aStartOffset, aEndOffset);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::pasteText(long aOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidOffset(aOffset))
+ return E_INVALIDARG;
+
+ textAcc->PasteText(aOffset);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::replaceText(long aStartOffset, long aEndOffset,
+ BSTR *aText)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidRange(aStartOffset, aEndOffset))
+ return E_INVALIDARG;
+
+ textAcc->DeleteText(aStartOffset, aEndOffset);
+
+ uint32_t length = ::SysStringLen(*aText);
+ nsAutoString text(*aText, length);
+ textAcc->InsertText(text, aStartOffset);
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::setAttributes(long aStartOffset, long aEndOffset,
+ BSTR *aAttributes)
+{
+ return E_NOTIMPL;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleEditableText.h b/accessible/windows/ia2/ia2AccessibleEditableText.h
new file mode 100644
index 000000000..a1501ca51
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleEditableText.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _ACCESSIBLE_EDITABLETEXT_H
+#define _ACCESSIBLE_EDITABLETEXT_H
+
+#include "nsISupports.h"
+
+#include "AccessibleEditableText.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ia2AccessibleEditableText: public IAccessibleEditableText
+{
+public:
+
+ // IAccessibleEditableText
+ virtual HRESULT STDMETHODCALLTYPE copyText(
+ /* [in] */ long startOffset,
+ /* [in] */ long endOffset);
+
+ virtual HRESULT STDMETHODCALLTYPE deleteText(
+ /* [in] */ long startOffset,
+ /* [in] */ long endOffset);
+
+ virtual HRESULT STDMETHODCALLTYPE insertText(
+ /* [in] */ long offset,
+ /* [in] */ BSTR *text);
+
+ virtual HRESULT STDMETHODCALLTYPE cutText(
+ /* [in] */ long startOffset,
+ /* [in] */ long endOffset);
+
+ virtual HRESULT STDMETHODCALLTYPE pasteText(
+ /* [in] */ long offset);
+
+ virtual HRESULT STDMETHODCALLTYPE replaceText(
+ /* [in] */ long startOffset,
+ /* [in] */ long endOffset,
+ /* [in] */ BSTR *text);
+
+ virtual HRESULT STDMETHODCALLTYPE setAttributes(
+ /* [in] */ long startOffset,
+ /* [in] */ long endOffset,
+ /* [in] */ BSTR *attributes);
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleHyperlink.cpp b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp
new file mode 100644
index 000000000..c6d564103
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp
@@ -0,0 +1,205 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Accessible2.h"
+#include "AccessibleHyperlink.h"
+#include "AccessibleHyperlink_i.c"
+
+#include "AccessibleWrap.h"
+#include "IUnknownImpl.h"
+#include "nsIURI.h"
+
+using namespace mozilla::a11y;
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleHyperlink::QueryInterface(REFIID iid, void** ppv)
+{
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleHyperlink == iid) {
+ auto accWrap = static_cast<AccessibleWrap*>(this);
+ if (accWrap->IsProxy() ?
+ !(accWrap->ProxyInterfaces() & Interfaces::HYPERLINK) :
+ !accWrap->IsLink())
+ return E_NOINTERFACE;
+
+ *ppv = static_cast<IAccessibleHyperlink*>(this);
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return ia2AccessibleAction::QueryInterface(iid, ppv);
+}
+
+// IAccessibleHyperlink
+
+STDMETHODIMP
+ia2AccessibleHyperlink::get_anchor(long aIndex, VARIANT* aAnchor)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAnchor)
+ return E_INVALIDARG;
+
+ VariantInit(aAnchor);
+
+ Accessible* thisObj = static_cast<AccessibleWrap*>(this);
+ MOZ_ASSERT(!thisObj->IsProxy());
+
+ if (thisObj->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount()))
+ return E_INVALIDARG;
+
+ if (!thisObj->IsLink())
+ return S_FALSE;
+
+ AccessibleWrap* anchor =
+ static_cast<AccessibleWrap*>(thisObj->AnchorAt(aIndex));
+ if (!anchor)
+ return S_FALSE;
+
+ void* instancePtr = nullptr;
+ HRESULT result = anchor->QueryInterface(IID_IUnknown, &instancePtr);
+ if (FAILED(result))
+ return result;
+
+ aAnchor->punkVal = static_cast<IUnknown*>(instancePtr);
+ aAnchor->vt = VT_UNKNOWN;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleHyperlink::get_anchorTarget(long aIndex, VARIANT* aAnchorTarget)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAnchorTarget) {
+ return E_INVALIDARG;
+ }
+
+ VariantInit(aAnchorTarget);
+
+ Accessible* thisObj = static_cast<AccessibleWrap*>(this);
+ nsAutoCString uriStr;
+ MOZ_ASSERT(!thisObj->IsProxy());
+ if (thisObj->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount())) {
+ return E_INVALIDARG;
+ }
+
+ if (!thisObj->IsLink()) {
+ return S_FALSE;
+ }
+
+ nsCOMPtr<nsIURI> uri = thisObj->AnchorURIAt(aIndex);
+ if (!uri) {
+ return S_FALSE;
+ }
+
+ nsresult rv = uri->GetSpec(uriStr);
+ if (NS_FAILED(rv)) {
+ return GetHRESULT(rv);
+ }
+
+ nsAutoString stringURI;
+ AppendUTF8toUTF16(uriStr, stringURI);
+
+ aAnchorTarget->vt = VT_BSTR;
+ aAnchorTarget->bstrVal = ::SysAllocStringLen(stringURI.get(),
+ stringURI.Length());
+ return aAnchorTarget->bstrVal ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleHyperlink::get_startIndex(long* aIndex)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aIndex)
+ return E_INVALIDARG;
+
+ *aIndex = 0;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ Accessible* thisObj = static_cast<AccessibleWrap*>(this);
+ if (thisObj->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!thisObj->IsLink())
+ return S_FALSE;
+
+ *aIndex = thisObj->StartOffset();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleHyperlink::get_endIndex(long* aIndex)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aIndex)
+ return E_INVALIDARG;
+
+ *aIndex = 0;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ Accessible* thisObj = static_cast<AccessibleWrap*>(this);
+ if (thisObj->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!thisObj->IsLink())
+ return S_FALSE;
+
+ *aIndex = thisObj->EndOffset();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleHyperlink::get_valid(boolean* aValid)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aValid)
+ return E_INVALIDARG;
+
+ *aValid = false;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ Accessible* thisObj = static_cast<AccessibleWrap*>(this);
+ if (thisObj->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!thisObj->IsLink())
+ return S_FALSE;
+
+ *aValid = thisObj->IsLinkValid();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
diff --git a/accessible/windows/ia2/ia2AccessibleHyperlink.h b/accessible/windows/ia2/ia2AccessibleHyperlink.h
new file mode 100644
index 000000000..dc34f5bc9
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleHyperlink.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _ACCESSIBLE_HYPERLINK_H
+#define _ACCESSIBLE_HYPERLINK_H
+
+#include "nsISupports.h"
+
+#include "ia2AccessibleAction.h"
+#include "AccessibleHyperlink.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ia2AccessibleHyperlink : public ia2AccessibleAction,
+ public IAccessibleHyperlink
+{
+public:
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID, void**);
+
+ // IAccessibleAction
+ FORWARD_IACCESSIBLEACTION(ia2AccessibleAction)
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_anchor(
+ /* [in] */ long index,
+ /* [retval][out] */ VARIANT *anchor);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_anchorTarget(
+ /* [in] */ long index,
+ /* [retval][out] */ VARIANT *anchorTarget);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_startIndex(
+ /* [retval][out] */ long *index);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_endIndex(
+ /* [retval][out] */ long *index);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_valid(
+ /* [retval][out] */ boolean *valid);
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleHypertext.cpp b/accessible/windows/ia2/ia2AccessibleHypertext.cpp
new file mode 100644
index 000000000..f4b3bdaf2
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleHypertext.cpp
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleHypertext.h"
+
+#include "AccessibleHypertext_i.c"
+
+#include "HyperTextAccessibleWrap.h"
+#include "IUnknownImpl.h"
+
+using namespace mozilla::a11y;
+
+// IAccessibleHypertext
+
+STDMETHODIMP
+ia2AccessibleHypertext::get_nHyperlinks(long* aHyperlinkCount)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aHyperlinkCount)
+ return E_INVALIDARG;
+
+ *aHyperlinkCount = 0;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessibleWrap* hyperText = static_cast<HyperTextAccessibleWrap*>(this);
+ if (hyperText->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ *aHyperlinkCount = hyperText->LinkCount();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleHypertext::get_hyperlink(long aLinkIndex,
+ IAccessibleHyperlink** aHyperlink)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aHyperlink)
+ return E_INVALIDARG;
+
+ *aHyperlink = nullptr;
+
+ AccessibleWrap* hyperLink;
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+ HyperTextAccessibleWrap* hyperText = static_cast<HyperTextAccessibleWrap*>(this);
+ if (hyperText->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ hyperLink = static_cast<AccessibleWrap*>(hyperText->LinkAt(aLinkIndex));
+
+ if (!hyperLink)
+ return E_FAIL;
+
+ *aHyperlink =
+ static_cast<IAccessibleHyperlink*>(hyperLink);
+ (*aHyperlink)->AddRef();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleHypertext::get_hyperlinkIndex(long aCharIndex, long* aHyperlinkIndex)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aHyperlinkIndex)
+ return E_INVALIDARG;
+
+ *aHyperlinkIndex = 0;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessibleWrap* hyperAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (hyperAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ *aHyperlinkIndex = hyperAcc->LinkIndexAtOffset(aCharIndex);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
diff --git a/accessible/windows/ia2/ia2AccessibleHypertext.h b/accessible/windows/ia2/ia2AccessibleHypertext.h
new file mode 100644
index 000000000..af5c209b4
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleHypertext.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _ACCESSIBLE_HYPERTEXT_H
+#define _ACCESSIBLE_HYPERTEXT_H
+
+#include "nsISupports.h"
+
+#include "ia2AccessibleText.h"
+#include "AccessibleHypertext.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ia2AccessibleHypertext : public ia2AccessibleText,
+ public IAccessibleHypertext
+{
+public:
+
+ // IAccessibleText
+ FORWARD_IACCESSIBLETEXT(ia2AccessibleText)
+
+ // IAccessibleHypertext
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nHyperlinks(
+ /* [retval][out] */ long* hyperlinkCount);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlink(
+ /* [in] */ long index,
+ /* [retval][out] */ IAccessibleHyperlink** hyperlink);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlinkIndex(
+ /* [in] */ long charIndex,
+ /* [retval][out] */ long* hyperlinkIndex);
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleImage.cpp b/accessible/windows/ia2/ia2AccessibleImage.cpp
new file mode 100644
index 000000000..989fde925
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleImage.cpp
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleImage.h"
+
+#include "AccessibleImage_i.c"
+
+#include "ImageAccessibleWrap.h"
+#include "IUnknownImpl.h"
+#include "nsIAccessibleTypes.h"
+
+#include "nsString.h"
+#include "nsIURI.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleImage::QueryInterface(REFIID iid, void** ppv)
+{
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleImage == iid) {
+ *ppv = static_cast<IAccessibleImage*>(this);
+ (static_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+// IAccessibleImage
+
+STDMETHODIMP
+ia2AccessibleImage::get_description(BSTR* aDescription)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aDescription)
+ return E_INVALIDARG;
+
+ *aDescription = nullptr;
+
+ ImageAccessibleWrap* acc = static_cast<ImageAccessibleWrap*>(this);
+ if (acc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString description;
+ acc->Name(description);
+ if (description.IsEmpty())
+ return S_FALSE;
+
+ *aDescription = ::SysAllocStringLen(description.get(), description.Length());
+ return *aDescription ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleImage::get_imagePosition(enum IA2CoordinateType aCoordType,
+ long* aX,
+ long* aY)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aX || !aY)
+ return E_INVALIDARG;
+
+ *aX = 0;
+ *aY = 0;
+
+ ImageAccessibleWrap* imageAcc = static_cast<ImageAccessibleWrap*>(this);
+ if (imageAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
+ nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
+ nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+
+ nsIntPoint pos = imageAcc->Position(geckoCoordType);
+ *aX = pos.x;
+ *aY = pos.y;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleImage::get_imageSize(long* aHeight, long* aWidth)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aHeight || !aWidth)
+ return E_INVALIDARG;
+
+ *aHeight = 0;
+ *aWidth = 0;
+
+ ImageAccessibleWrap* imageAcc = static_cast<ImageAccessibleWrap*>(this);
+ if (imageAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsIntSize size = imageAcc->Size();
+ *aHeight = size.width;
+ *aWidth = size.height;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
diff --git a/accessible/windows/ia2/ia2AccessibleImage.h b/accessible/windows/ia2/ia2AccessibleImage.h
new file mode 100644
index 000000000..d065cf34c
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleImage.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _ACCESSIBLE_IMAGE_H
+#define _ACCESSIBLE_IMAGE_H
+
+#include "AccessibleImage.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ia2AccessibleImage : public IAccessibleImage
+{
+public:
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID, void**);
+
+ // IAccessibleImage
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_description(
+ /* [retval][out] */ BSTR *description);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_imagePosition(
+ /* [in] */ enum IA2CoordinateType coordinateType,
+ /* [out] */ long *x,
+ /* [retval][out] */ long *y);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_imageSize(
+ /* [out] */ long *height,
+ /* [retval][out] */ long *width);
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleRelation.cpp b/accessible/windows/ia2/ia2AccessibleRelation.cpp
new file mode 100644
index 000000000..cc6fd83c8
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleRelation.cpp
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleRelation.h"
+
+#include "Relation.h"
+#include "nsID.h"
+
+#include "AccessibleRelation_i.c"
+
+using namespace mozilla::a11y;
+
+ia2AccessibleRelation::ia2AccessibleRelation(RelationType aType, Relation* aRel) :
+ mType(aType)
+{
+ Accessible* target = nullptr;
+ while ((target = aRel->Next()))
+ mTargets.AppendElement(target);
+}
+
+// IUnknown
+
+IMPL_IUNKNOWN_QUERY_HEAD(ia2AccessibleRelation)
+ IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleRelation)
+ IMPL_IUNKNOWN_QUERY_IFACE(IUnknown)
+IMPL_IUNKNOWN_QUERY_TAIL
+
+// IAccessibleRelation
+
+STDMETHODIMP
+ia2AccessibleRelation::get_relationType(BSTR* aRelationType)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRelationType)
+ return E_INVALIDARG;
+
+ *aRelationType = nullptr;
+
+#define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \
+ case RelationType::geckoType: \
+ *aRelationType = ::SysAllocString(ia2Type); \
+ break;
+
+ switch (mType) {
+#include "RelationTypeMap.h"
+ }
+
+ return *aRelationType ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleRelation::get_localizedRelationType(BSTR *aLocalizedRelationType)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aLocalizedRelationType)
+ return E_INVALIDARG;
+
+ *aLocalizedRelationType = nullptr;
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleRelation::get_nTargets(long *aNTargets)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNTargets)
+ return E_INVALIDARG;
+
+ *aNTargets = mTargets.Length();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleRelation::get_target(long aTargetIndex, IUnknown **aTarget)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (aTargetIndex < 0 || (uint32_t)aTargetIndex >= mTargets.Length() || !aTarget)
+ return E_INVALIDARG;
+
+ AccessibleWrap* target =
+ static_cast<AccessibleWrap*>(mTargets[aTargetIndex].get());
+ *aTarget = static_cast<IAccessible*>(target);
+ (*aTarget)->AddRef();
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleRelation::get_targets(long aMaxTargets, IUnknown **aTargets,
+ long *aNTargets)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNTargets || !aTargets)
+ return E_INVALIDARG;
+
+ *aNTargets = 0;
+ long maxTargets = mTargets.Length();
+ if (maxTargets > aMaxTargets)
+ maxTargets = aMaxTargets;
+
+ for (long idx = 0; idx < maxTargets; idx++)
+ get_target(idx, aTargets + idx);
+
+ *aNTargets = maxTargets;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
diff --git a/accessible/windows/ia2/ia2AccessibleRelation.h b/accessible/windows/ia2/ia2AccessibleRelation.h
new file mode 100644
index 000000000..faaa31cb0
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleRelation.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _NS_ACCESSIBLE_RELATION_WRAP_H
+#define _NS_ACCESSIBLE_RELATION_WRAP_H
+
+#include "Accessible.h"
+#include "IUnknownImpl.h"
+
+#include <utility>
+#include "nsTArray.h"
+
+#include "AccessibleRelation.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ia2AccessibleRelation final : public IAccessibleRelation
+{
+public:
+ ia2AccessibleRelation(RelationType aType, Relation* aRel);
+
+ ia2AccessibleRelation(RelationType aType,
+ nsTArray<RefPtr<Accessible>>&& aTargets) :
+ mType(aType), mTargets(Move(aTargets)) {}
+
+ // IUnknown
+ DECL_IUNKNOWN
+
+ // IAccessibleRelation
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relationType(
+ /* [retval][out] */ BSTR *relationType);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedRelationType(
+ /* [retval][out] */ BSTR *localizedRelationType);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nTargets(
+ /* [retval][out] */ long *nTargets);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_target(
+ /* [in] */ long targetIndex,
+ /* [retval][out] */ IUnknown **target);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_targets(
+ /* [in] */ long maxTargets,
+ /* [length_is][size_is][out] */ IUnknown **target,
+ /* [retval][out] */ long *nTargets);
+
+ inline bool HasTargets() const
+ { return mTargets.Length(); }
+
+private:
+ ia2AccessibleRelation();
+ ia2AccessibleRelation(const ia2AccessibleRelation&);
+ ia2AccessibleRelation& operator = (const ia2AccessibleRelation&);
+
+ RelationType mType;
+ nsTArray<RefPtr<Accessible> > mTargets;
+};
+
+
+/**
+ * Gecko to IAccessible2 relation types map.
+ */
+
+const WCHAR *const IA2_RELATION_NULL = L"";
+
+#define RELATIONTYPE(geckoType, name, atkType, msaaType, ia2Type) \
+ std::pair<RelationType, const WCHAR *const>(RelationType::geckoType, ia2Type),
+
+static const std::pair<RelationType, const WCHAR *const> sRelationTypePairs[] = {
+#include "RelationTypeMap.h"
+};
+
+#undef RELATIONTYPE
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
+
diff --git a/accessible/windows/ia2/ia2AccessibleTable.cpp b/accessible/windows/ia2/ia2AccessibleTable.cpp
new file mode 100644
index 000000000..6ac6bbab4
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleTable.cpp
@@ -0,0 +1,747 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleTable.h"
+
+#include "Accessible2.h"
+#include "AccessibleTable_i.c"
+#include "AccessibleTable2_i.c"
+
+#include "AccessibleWrap.h"
+#include "IUnknownImpl.h"
+#include "Statistics.h"
+#include "TableAccessible.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+using namespace mozilla::a11y;
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleTable::QueryInterface(REFIID iid, void** ppv)
+{
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleTable == iid) {
+ statistics::IAccessibleTableUsed();
+ *ppv = static_cast<IAccessibleTable*>(this);
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ if (IID_IAccessibleTable2 == iid) {
+ *ppv = static_cast<IAccessibleTable2*>(this);
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessibleTable
+
+STDMETHODIMP
+ia2AccessibleTable::get_accessibleAt(long aRowIdx, long aColIdx,
+ IUnknown** aAccessible)
+{
+ return get_cellAt(aRowIdx, aColIdx, aAccessible);
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_caption(IUnknown** aAccessible)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAccessible)
+ return E_INVALIDARG;
+
+ *aAccessible = nullptr;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ AccessibleWrap* caption = static_cast<AccessibleWrap*>(mTable->Caption());
+ if (!caption)
+ return S_FALSE;
+
+ (*aAccessible = static_cast<IAccessible*>(caption))->AddRef();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_childIndex(long aRowIdx, long aColIdx,
+ long* aChildIdx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aChildIdx)
+ return E_INVALIDARG;
+
+ *aChildIdx = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || aColIdx < 0 ||
+ static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() ||
+ static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
+ return E_INVALIDARG;
+
+ *aChildIdx = mTable->CellIndexAt(aRowIdx, aColIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_columnDescription(long aColIdx, BSTR* aDescription)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aDescription)
+ return E_INVALIDARG;
+
+ *aDescription = nullptr;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
+ return E_INVALIDARG;
+
+ nsAutoString descr;
+ mTable->ColDescription(aColIdx, descr);
+ if (descr.IsEmpty())
+ return S_FALSE;
+
+ *aDescription = ::SysAllocStringLen(descr.get(), descr.Length());
+ return *aDescription ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_columnExtentAt(long aRowIdx, long aColIdx,
+ long* aSpan)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aSpan)
+ return E_INVALIDARG;
+
+ *aSpan = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || aColIdx < 0 ||
+ static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() ||
+ static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
+ return E_INVALIDARG;
+
+ *aSpan = mTable->ColExtentAt(aRowIdx, aColIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_columnHeader(IAccessibleTable** aAccessibleTable,
+ long* aStartingRowIndex)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAccessibleTable || !aStartingRowIndex)
+ return E_INVALIDARG;
+
+ *aAccessibleTable = nullptr;
+ *aStartingRowIndex = -1;
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_columnIndex(long aCellIdx, long* aColIdx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aColIdx)
+ return E_INVALIDARG;
+
+ *aColIdx = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aCellIdx < 0 ||
+ static_cast<uint32_t>(aCellIdx) >= mTable->ColCount() * mTable->RowCount())
+ return E_INVALIDARG;
+
+ *aColIdx = mTable->ColIndexAt(aCellIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nColumns(long* aColCount)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aColCount)
+ return E_INVALIDARG;
+
+ *aColCount = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aColCount = mTable->ColCount();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nRows(long* aRowCount)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRowCount)
+ return E_INVALIDARG;
+
+ *aRowCount = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aRowCount = mTable->RowCount();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nSelectedChildren(long* aChildCount)
+{
+ return get_nSelectedCells(aChildCount);
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nSelectedColumns(long* aColCount)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aColCount)
+ return E_INVALIDARG;
+
+ *aColCount = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aColCount = mTable->SelectedColCount();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nSelectedRows(long* aRowCount)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRowCount)
+ return E_INVALIDARG;
+
+ *aRowCount = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aRowCount = mTable->SelectedRowCount();
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowDescription(long aRowIdx, BSTR* aDescription)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aDescription)
+ return E_INVALIDARG;
+
+ *aDescription = nullptr;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
+ return E_INVALIDARG;
+
+ nsAutoString descr;
+ mTable->RowDescription(aRowIdx, descr);
+ if (descr.IsEmpty())
+ return S_FALSE;
+
+ *aDescription = ::SysAllocStringLen(descr.get(), descr.Length());
+ return *aDescription ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowExtentAt(long aRowIdx, long aColIdx, long* aSpan)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aSpan)
+ return E_INVALIDARG;
+
+ *aSpan = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || aColIdx < 0 ||
+ static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() ||
+ static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
+ return E_INVALIDARG;
+
+ *aSpan = mTable->RowExtentAt(aRowIdx, aColIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowHeader(IAccessibleTable** aAccessibleTable,
+ long* aStartingColumnIndex)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAccessibleTable || !aStartingColumnIndex)
+ return E_INVALIDARG;
+
+ *aAccessibleTable = nullptr;
+ *aStartingColumnIndex = -1;
+ return E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowIndex(long aCellIdx, long* aRowIdx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRowIdx)
+ return E_INVALIDARG;
+
+ *aRowIdx = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aCellIdx < 0 ||
+ static_cast<uint32_t>(aCellIdx) >= mTable->ColCount() * mTable->RowCount())
+ return E_INVALIDARG;
+
+ *aRowIdx = mTable->RowIndexAt(aCellIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedChildren(long aMaxChildren, long** aChildren,
+ long* aNChildren)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aChildren || !aNChildren)
+ return E_INVALIDARG;
+
+ *aChildren = nullptr;
+ *aNChildren = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<uint32_t, 30> cellIndices;
+ mTable->SelectedCellIndices(&cellIndices);
+
+ uint32_t maxCells = cellIndices.Length();
+ if (maxCells == 0)
+ return S_FALSE;
+
+ *aChildren = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCells));
+ *aNChildren = maxCells;
+ for (uint32_t i = 0; i < maxCells; i++)
+ (*aChildren)[i] = cellIndices[i];
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedColumns(long aMaxColumns, long** aColumns,
+ long* aNColumns)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ return get_selectedColumns(aColumns, aNColumns);
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedRows(long aMaxRows, long** aRows, long* aNRows)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ return get_selectedRows(aRows, aNRows);
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_summary(IUnknown** aAccessible)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAccessible)
+ return E_INVALIDARG;
+
+ // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to
+ // link an accessible object to specify a summary. There is closes method
+ // in Table::summary to get a summary as a string which is not mapped
+ // directly to IAccessible2.
+
+ *aAccessible = nullptr;
+ return S_FALSE;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_isColumnSelected(long aColIdx, boolean* aIsSelected)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aIsSelected)
+ return E_INVALIDARG;
+
+ *aIsSelected = false;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
+ return E_INVALIDARG;
+
+ *aIsSelected = mTable->IsColSelected(aColIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_isRowSelected(long aRowIdx, boolean* aIsSelected)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aIsSelected)
+ return E_INVALIDARG;
+
+ *aIsSelected = false;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
+ return E_INVALIDARG;
+
+ *aIsSelected = mTable->IsRowSelected(aRowIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_isSelected(long aRowIdx, long aColIdx,
+ boolean* aIsSelected)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aIsSelected)
+ return E_INVALIDARG;
+
+ *aIsSelected = false;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || aColIdx < 0 ||
+ static_cast<uint32_t>(aColIdx) >= mTable->ColCount() ||
+ static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
+ return E_INVALIDARG;
+
+ *aIsSelected = mTable->IsCellSelected(aRowIdx, aColIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::selectRow(long aRowIdx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
+ return E_INVALIDARG;
+
+ mTable->SelectRow(aRowIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::selectColumn(long aColIdx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
+ return E_INVALIDARG;
+
+ mTable->SelectCol(aColIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::unselectRow(long aRowIdx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
+ return E_INVALIDARG;
+
+ mTable->UnselectRow(aRowIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::unselectColumn(long aColIdx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
+ return E_INVALIDARG;
+
+ mTable->UnselectCol(aColIdx);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowColumnExtentsAtIndex(long aCellIdx, long* aRowIdx,
+ long* aColIdx,
+ long* aRowExtents,
+ long* aColExtents,
+ boolean* aIsSelected)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected)
+ return E_INVALIDARG;
+
+ *aRowIdx = 0;
+ *aColIdx = 0;
+ *aRowExtents = 0;
+ *aColExtents = 0;
+ *aIsSelected = false;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aCellIdx < 0 ||
+ static_cast<uint32_t>(aCellIdx) >= mTable->ColCount() * mTable->RowCount())
+ return E_INVALIDARG;
+
+ int32_t colIdx = 0, rowIdx = 0;
+ mTable->RowAndColIndicesAt(aCellIdx, &rowIdx, &colIdx);
+ *aRowIdx = rowIdx;
+ *aColIdx = colIdx;
+ *aRowExtents = mTable->RowExtentAt(rowIdx, colIdx);
+ *aColExtents = mTable->ColExtentAt(rowIdx, colIdx);
+ *aIsSelected = mTable->IsCellSelected(rowIdx, colIdx);
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_modelChange(IA2TableModelChange* aModelChange)
+{
+ return E_NOTIMPL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessibleTable2
+
+STDMETHODIMP
+ia2AccessibleTable::get_cellAt(long aRowIdx, long aColIdx, IUnknown** aCell)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aCell)
+ return E_INVALIDARG;
+
+ *aCell = nullptr;
+
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ AccessibleWrap* cell =
+ static_cast<AccessibleWrap*>(mTable->CellAt(aRowIdx, aColIdx));
+ if (!cell)
+ return E_INVALIDARG;
+
+ (*aCell = static_cast<IAccessible*>(cell))->AddRef();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nSelectedCells(long* aCellCount)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aCellCount)
+ return E_INVALIDARG;
+
+ *aCellCount = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aCellCount = mTable->SelectedCellCount();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedCells(IUnknown*** aCells, long* aNSelectedCells)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aCells || !aNSelectedCells)
+ return E_INVALIDARG;
+
+ *aCells = nullptr;
+ *aNSelectedCells = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<Accessible*, 30> cells;
+ mTable->SelectedCells(&cells);
+ if (cells.IsEmpty())
+ return S_FALSE;
+
+ *aCells =
+ static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) *
+ cells.Length()));
+ if (!*aCells)
+ return E_OUTOFMEMORY;
+
+ for (uint32_t i = 0; i < cells.Length(); i++) {
+ (*aCells)[i] =
+ static_cast<IAccessible*>(static_cast<AccessibleWrap*>(cells[i]));
+ ((*aCells)[i])->AddRef();
+ }
+
+ *aNSelectedCells = cells.Length();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedColumns(long** aColumns, long* aNColumns)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aColumns || !aNColumns)
+ return E_INVALIDARG;
+
+ *aColumns = nullptr;
+ *aNColumns = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<uint32_t, 30> colIndices;
+ mTable->SelectedColIndices(&colIndices);
+
+ uint32_t maxCols = colIndices.Length();
+ if (maxCols == 0)
+ return S_FALSE;
+
+ *aColumns = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCols));
+ *aNColumns = maxCols;
+ for (uint32_t i = 0; i < maxCols; i++)
+ (*aColumns)[i] = colIndices[i];
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedRows(long** aRows, long* aNRows)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRows || !aNRows)
+ return E_INVALIDARG;
+
+ *aRows = nullptr;
+ *aNRows = 0;
+ if (!mTable)
+ return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<uint32_t, 30> rowIndices;
+ mTable->SelectedRowIndices(&rowIndices);
+
+ uint32_t maxRows = rowIndices.Length();
+ if (maxRows == 0)
+ return S_FALSE;
+
+ *aRows = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxRows));
+ *aNRows = maxRows;
+ for (uint32_t i = 0; i < maxRows; i++)
+ (*aRows)[i] = rowIndices[i];
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
diff --git a/accessible/windows/ia2/ia2AccessibleTable.h b/accessible/windows/ia2/ia2AccessibleTable.h
new file mode 100644
index 000000000..6738e2dfc
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleTable.h
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _ACCESSIBLE_TABLE_H
+#define _ACCESSIBLE_TABLE_H
+
+#include "AccessibleTable.h"
+#include "AccessibleTable2.h"
+
+namespace mozilla {
+namespace a11y {
+
+class TableAccessible;
+
+class ia2AccessibleTable : public IAccessibleTable,
+ public IAccessibleTable2
+{
+public:
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID, void**);
+
+ // IAccessibleTable
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_accessibleAt(
+ /* [in] */ long row,
+ /* [in] */ long column,
+ /* [retval][out] */ IUnknown **accessible);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_caption(
+ /* [retval][out] */ IUnknown **accessible);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_childIndex(
+ /* [in] */ long rowIndex,
+ /* [in] */ long columnIndex,
+ /* [retval][out] */ long *childIndex);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnDescription(
+ /* [in] */ long column,
+ /* [retval][out] */ BSTR *description);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnExtentAt(
+ /* [in] */ long row,
+ /* [in] */ long column,
+ /* [retval][out] */ long *nColumnsSpanned);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnHeader(
+ /* [out] */ IAccessibleTable **accessibleTable,
+ /* [retval][out] */ long *startingRowIndex);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnIndex(
+ /* [in] */ long childIndex,
+ /* [retval][out] */ long *columnIndex);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nColumns(
+ /* [retval][out] */ long *columnCount);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nRows(
+ /* [retval][out] */ long *rowCount);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedChildren(
+ /* [retval][out] */ long *childCount);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedColumns(
+ /* [retval][out] */ long *columnCount);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedRows(
+ /* [retval][out] */ long *rowCount);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowDescription(
+ /* [in] */ long row,
+ /* [retval][out] */ BSTR *description);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowExtentAt(
+ /* [in] */ long row,
+ /* [in] */ long column,
+ /* [retval][out] */ long *nRowsSpanned);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowHeader(
+ /* [out] */ IAccessibleTable **accessibleTable,
+ /* [retval][out] */ long *startingColumnIndex);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowIndex(
+ /* [in] */ long childIndex,
+ /* [retval][out] */ long *rowIndex);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedChildren(
+ /* [in] */ long maxChildren,
+ /* [length_is][length_is][size_is][size_is][out] */ long **children,
+ /* [retval][out] */ long *nChildren);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedColumns(
+ /* [in] */ long maxColumns,
+ /* [length_is][length_is][size_is][size_is][out] */ long **columns,
+ /* [retval][out] */ long *nColumns);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedRows(
+ /* [in] */ long maxRows,
+ /* [length_is][length_is][size_is][size_is][out] */ long **rows,
+ /* [retval][out] */ long *nRows);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_summary(
+ /* [retval][out] */ IUnknown **accessible);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isColumnSelected(
+ /* [in] */ long column,
+ /* [retval][out] */ boolean *isSelected);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isRowSelected(
+ /* [in] */ long row,
+ /* [retval][out] */ boolean *isSelected);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isSelected(
+ /* [in] */ long row,
+ /* [in] */ long column,
+ /* [retval][out] */ boolean *isSelected);
+
+ virtual HRESULT STDMETHODCALLTYPE selectRow(
+ /* [in] */ long row);
+
+ virtual HRESULT STDMETHODCALLTYPE selectColumn(
+ /* [in] */ long column);
+
+ virtual HRESULT STDMETHODCALLTYPE unselectRow(
+ /* [in] */ long row);
+
+ virtual HRESULT STDMETHODCALLTYPE unselectColumn(
+ /* [in] */ long column);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowColumnExtentsAtIndex(
+ /* [in] */ long index,
+ /* [out] */ long *row,
+ /* [out] */ long *column,
+ /* [out] */ long *rowExtents,
+ /* [out] */ long *columnExtents,
+ /* [retval][out] */ boolean *isSelected);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_modelChange(
+ /* [retval][out] */ IA2TableModelChange *modelChange);
+
+
+ // IAccessibleTable2
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_cellAt(
+ /* [in] */ long row,
+ /* [in] */ long column,
+ /* [out, retval] */ IUnknown **cell);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedCells(
+ /* [out, retval] */ long *cellCount);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedCells(
+ /* [out, size_is(,*nSelectedCells,)] */ IUnknown ***cells,
+ /* [out, retval] */ long *nSelectedCells);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedColumns(
+ /* [out, size_is(,*nColumns)] */ long **selectedColumns,
+ /* [out, retval] */ long *nColumns);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedRows(
+ /* [out, size_is(,*nRows)] */ long **selectedRows,
+ /* [out, retval] */ long *nRows);
+
+protected:
+ ia2AccessibleTable(TableAccessible* aTable) : mTable(aTable) {}
+
+ TableAccessible* mTable;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleTableCell.cpp b/accessible/windows/ia2/ia2AccessibleTableCell.cpp
new file mode 100644
index 000000000..e625a7049
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleTableCell.cpp
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleTableCell.h"
+
+#include "Accessible2.h"
+#include "AccessibleTable2_i.c"
+#include "AccessibleTableCell_i.c"
+
+#include "AccessibleWrap.h"
+#include "TableAccessible.h"
+#include "TableCellAccessible.h"
+#include "IUnknownImpl.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+using namespace mozilla::a11y;
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleTableCell::QueryInterface(REFIID iid, void** ppv)
+{
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleTableCell == iid) {
+ *ppv = static_cast<IAccessibleTableCell*>(this);
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessibleTableCell
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_table(IUnknown** aTable)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aTable)
+ return E_INVALIDARG;
+
+ *aTable = nullptr;
+ if (!mTableCell)
+ return CO_E_OBJNOTCONNECTED;
+
+ TableAccessible* table = mTableCell->Table();
+ if (!table)
+ return E_FAIL;
+
+ AccessibleWrap* wrap = static_cast<AccessibleWrap*>(table->AsAccessible());
+ *aTable = static_cast<IAccessible*>(wrap);
+ (*aTable)->AddRef();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_columnExtent(long* aSpan)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aSpan)
+ return E_INVALIDARG;
+
+ *aSpan = 0;
+ if (!mTableCell)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aSpan = mTableCell->ColExtent();
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_columnHeaderCells(IUnknown*** aCellAccessibles,
+ long* aNColumnHeaderCells)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aCellAccessibles || !aNColumnHeaderCells)
+ return E_INVALIDARG;
+
+ *aCellAccessibles = nullptr;
+ *aNColumnHeaderCells = 0;
+ if (!mTableCell)
+ return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<Accessible*, 10> cells;
+ mTableCell->ColHeaderCells(&cells);
+
+ *aNColumnHeaderCells = cells.Length();
+ *aCellAccessibles =
+ static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) *
+ cells.Length()));
+
+ if (!*aCellAccessibles)
+ return E_OUTOFMEMORY;
+
+ for (uint32_t i = 0; i < cells.Length(); i++) {
+ AccessibleWrap* cell = static_cast<AccessibleWrap*>(cells[i]);
+ (*aCellAccessibles)[i] = static_cast<IAccessible*>(cell);
+ (*aCellAccessibles)[i]->AddRef();
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_columnIndex(long* aColIdx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aColIdx)
+ return E_INVALIDARG;
+
+ *aColIdx = -1;
+ if (!mTableCell)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aColIdx = mTableCell->ColIdx();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_rowExtent(long* aSpan)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aSpan)
+ return E_INVALIDARG;
+
+ *aSpan = 0;
+ if (!mTableCell)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aSpan = mTableCell->RowExtent();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_rowHeaderCells(IUnknown*** aCellAccessibles,
+ long* aNRowHeaderCells)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aCellAccessibles || !aNRowHeaderCells)
+ return E_INVALIDARG;
+
+ *aCellAccessibles = nullptr;
+ *aNRowHeaderCells = 0;
+ if (!mTableCell)
+ return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<Accessible*, 10> cells;
+ mTableCell->RowHeaderCells(&cells);
+
+ *aNRowHeaderCells = cells.Length();
+ *aCellAccessibles =
+ static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) *
+ cells.Length()));
+ if (!*aCellAccessibles)
+ return E_OUTOFMEMORY;
+
+ for (uint32_t i = 0; i < cells.Length(); i++) {
+ AccessibleWrap* cell = static_cast<AccessibleWrap*>(cells[i]);
+ (*aCellAccessibles)[i] = static_cast<IAccessible*>(cell);
+ (*aCellAccessibles)[i]->AddRef();
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_rowIndex(long* aRowIdx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRowIdx)
+ return E_INVALIDARG;
+
+ *aRowIdx = -1;
+ if (!mTableCell)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aRowIdx = mTableCell->RowIdx();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_rowColumnExtents(long* aRowIdx, long* aColIdx,
+ long* aRowExtents,
+ long* aColExtents,
+ boolean* aIsSelected)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected)
+ return E_INVALIDARG;
+
+ *aRowIdx = *aColIdx = *aRowExtents = *aColExtents = 0;
+ *aIsSelected = false;
+ if (!mTableCell)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aRowIdx = mTableCell->RowIdx();
+ *aColIdx = mTableCell->ColIdx();
+ *aRowExtents = mTableCell->RowExtent();
+ *aColExtents = mTableCell->ColExtent();
+ *aIsSelected = mTableCell->Selected();
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_isSelected(boolean* aIsSelected)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aIsSelected)
+ return E_INVALIDARG;
+
+ *aIsSelected = false;
+ if (!mTableCell)
+ return CO_E_OBJNOTCONNECTED;
+
+ *aIsSelected = mTableCell->Selected();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
diff --git a/accessible/windows/ia2/ia2AccessibleTableCell.h b/accessible/windows/ia2/ia2AccessibleTableCell.h
new file mode 100644
index 000000000..883ca2875
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleTableCell.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _ACCESSIBLE_TABLECELL_H
+#define _ACCESSIBLE_TABLECELL_H
+
+#include "AccessibleTableCell.h"
+
+namespace mozilla {
+namespace a11y {
+class TableCellAccessible;
+
+class ia2AccessibleTableCell : public IAccessibleTableCell
+{
+public:
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID, void**);
+
+ // IAccessibleTableCell
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_table(
+ /* [out, retval] */ IUnknown **table);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnExtent(
+ /* [out, retval] */ long *nColumnsSpanned);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnHeaderCells(
+ /* [out, size_is(,*nColumnHeaderCells,)] */ IUnknown ***cellAccessibles,
+ /* [out, retval] */ long *nColumnHeaderCells);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnIndex(
+ /* [out, retval] */ long *columnIndex);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowExtent(
+ /* [out, retval] */ long *nRowsSpanned);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowHeaderCells(
+ /* [out, size_is(,*nRowHeaderCells,)] */ IUnknown ***cellAccessibles,
+ /* [out, retval] */ long *nRowHeaderCells);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowIndex(
+ /* [out, retval] */ long *rowIndex);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowColumnExtents(
+ /* [out] */ long *row,
+ /* [out] */ long *column,
+ /* [out] */ long *rowExtents,
+ /* [out] */ long *columnExtents,
+ /* [out, retval] */ boolean *isSelected);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isSelected(
+ /* [out, retval] */ boolean *isSelected);
+
+protected:
+ ia2AccessibleTableCell(TableCellAccessible* aTableCell) :
+ mTableCell(aTableCell) {}
+
+ TableCellAccessible* mTableCell;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleText.cpp b/accessible/windows/ia2/ia2AccessibleText.cpp
new file mode 100644
index 000000000..7ac766f30
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleText.cpp
@@ -0,0 +1,598 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleText.h"
+
+#include "Accessible2.h"
+#include "AccessibleText_i.c"
+
+#include "HyperTextAccessibleWrap.h"
+#include "HyperTextAccessible-inl.h"
+#include "ProxyWrappers.h"
+#include "mozilla/ClearOnShutdown.h"
+
+using namespace mozilla::a11y;
+
+StaticRefPtr<HyperTextAccessibleWrap> ia2AccessibleText::sLastTextChangeAcc;
+StaticAutoPtr<nsString> ia2AccessibleText::sLastTextChangeString;
+uint32_t ia2AccessibleText::sLastTextChangeStart = 0;
+uint32_t ia2AccessibleText::sLastTextChangeEnd = 0;
+bool ia2AccessibleText::sLastTextChangeWasInsert = false;
+
+// IAccessibleText
+
+STDMETHODIMP
+ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ return textAcc->AddToSelection(aStartOffset, aEndOffset) ?
+ S_OK : E_INVALIDARG;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_attributes(long aOffset, long *aStartOffset,
+ long *aEndOffset, BSTR *aTextAttributes)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aStartOffset || !aEndOffset || !aTextAttributes)
+ return E_INVALIDARG;
+
+ *aStartOffset = 0;
+ *aEndOffset = 0;
+ *aTextAttributes = nullptr;
+
+ int32_t startOffset = 0, endOffset = 0;
+ HRESULT hr;
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ nsCOMPtr<nsIPersistentProperties> attributes =
+ textAcc->TextAttributes(true, aOffset, &startOffset, &endOffset);
+
+ hr = AccessibleWrap::ConvertToIA2Attributes(attributes, aTextAttributes);
+ if (FAILED(hr))
+ return hr;
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_caretOffset(long *aOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aOffset)
+ return E_INVALIDARG;
+
+ *aOffset = -1;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ *aOffset = textAcc->CaretOffset();
+
+ return *aOffset != -1 ? S_OK : S_FALSE;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_characterExtents(long aOffset,
+ enum IA2CoordinateType aCoordType,
+ long* aX, long* aY,
+ long* aWidth, long* aHeight)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aX || !aY || !aWidth || !aHeight)
+ return E_INVALIDARG;
+ *aX = *aY = *aWidth = *aHeight = 0;
+
+ uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
+ nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
+ nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+ nsIntRect rect;
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ rect = textAcc->CharBounds(aOffset, geckoCoordType);
+
+ *aX = rect.x;
+ *aY = rect.y;
+ *aWidth = rect.width;
+ *aHeight = rect.height;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_nSelections(long* aNSelections)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNSelections)
+ return E_INVALIDARG;
+ *aNSelections = 0;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ *aNSelections = textAcc->SelectionCount();
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_offsetAtPoint(long aX, long aY,
+ enum IA2CoordinateType aCoordType,
+ long* aOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aOffset)
+ return E_INVALIDARG;
+ *aOffset = 0;
+
+ uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
+ nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
+ nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ *aOffset = textAcc->OffsetAtPoint(aX, aY, geckoCoordType);
+
+ return *aOffset == -1 ? S_FALSE : S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_selection(long aSelectionIndex, long* aStartOffset,
+ long* aEndOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aStartOffset || !aEndOffset)
+ return E_INVALIDARG;
+ *aStartOffset = *aEndOffset = 0;
+
+ int32_t startOffset = 0, endOffset = 0;
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (!textAcc->SelectionBoundsAt(aSelectionIndex, &startOffset, &endOffset)) {
+ return E_INVALIDARG;
+ }
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR* aText)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aText)
+ return E_INVALIDARG;
+
+ *aText = nullptr;
+
+ nsAutoString text;
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) {
+ return E_INVALIDARG;
+ }
+
+ textAcc->TextSubstring(aStartOffset, aEndOffset, text);
+
+ if (text.IsEmpty())
+ return S_FALSE;
+
+ *aText = ::SysAllocStringLen(text.get(), text.Length());
+ return *aText ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_textBeforeOffset(long aOffset,
+ enum IA2TextBoundaryType aBoundaryType,
+ long* aStartOffset, long* aEndOffset,
+ BSTR* aText)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aStartOffset || !aEndOffset || !aText)
+ return E_INVALIDARG;
+
+ *aStartOffset = *aEndOffset = 0;
+ *aText = nullptr;
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidOffset(aOffset))
+ return E_INVALIDARG;
+
+ nsAutoString text;
+ int32_t startOffset = 0, endOffset = 0;
+
+ if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
+ startOffset = 0;
+ endOffset = textAcc->CharacterCount();
+ textAcc->TextSubstring(startOffset, endOffset, text);
+ } else {
+ AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType);
+ if (boundaryType == -1)
+ return S_FALSE;
+
+ textAcc->TextBeforeOffset(aOffset, boundaryType, &startOffset, &endOffset, text);
+ }
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ if (text.IsEmpty())
+ return S_FALSE;
+
+ *aText = ::SysAllocStringLen(text.get(), text.Length());
+ return *aText ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_textAfterOffset(long aOffset,
+ enum IA2TextBoundaryType aBoundaryType,
+ long* aStartOffset, long* aEndOffset,
+ BSTR* aText)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aStartOffset || !aEndOffset || !aText)
+ return E_INVALIDARG;
+
+ *aStartOffset = 0;
+ *aEndOffset = 0;
+ *aText = nullptr;
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidOffset(aOffset))
+ return E_INVALIDARG;
+
+ nsAutoString text;
+ int32_t startOffset = 0, endOffset = 0;
+
+ if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
+ startOffset = 0;
+ endOffset = textAcc->CharacterCount();
+ textAcc->TextSubstring(startOffset, endOffset, text);
+ } else {
+ AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType);
+ if (boundaryType == -1)
+ return S_FALSE;
+ textAcc->TextAfterOffset(aOffset, boundaryType, &startOffset, &endOffset, text);
+ }
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ if (text.IsEmpty())
+ return S_FALSE;
+
+ *aText = ::SysAllocStringLen(text.get(), text.Length());
+ return *aText ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_textAtOffset(long aOffset,
+ enum IA2TextBoundaryType aBoundaryType,
+ long* aStartOffset, long* aEndOffset,
+ BSTR* aText)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aStartOffset || !aEndOffset || !aText)
+ return E_INVALIDARG;
+
+ *aStartOffset = *aEndOffset = 0;
+ *aText = nullptr;
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidOffset(aOffset))
+ return E_INVALIDARG;
+
+ nsAutoString text;
+ int32_t startOffset = 0, endOffset = 0;
+ if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
+ startOffset = 0;
+ endOffset = textAcc->CharacterCount();
+ textAcc->TextSubstring(startOffset, endOffset, text);
+ } else {
+ AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType);
+ if (boundaryType == -1)
+ return S_FALSE;
+ textAcc->TextAtOffset(aOffset, boundaryType, &startOffset, &endOffset, text);
+ }
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ if (text.IsEmpty())
+ return S_FALSE;
+
+ *aText = ::SysAllocStringLen(text.get(), text.Length());
+ return *aText ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::removeSelection(long aSelectionIndex)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ return textAcc->RemoveFromSelection(aSelectionIndex) ?
+ S_OK : E_INVALIDARG;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::setCaretOffset(long aOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidOffset(aOffset))
+ return E_INVALIDARG;
+
+ textAcc->SetCaretOffset(aOffset);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::setSelection(long aSelectionIndex, long aStartOffset,
+ long aEndOffset)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ return textAcc->SetSelectionBoundsAt(aSelectionIndex, aStartOffset, aEndOffset) ?
+ S_OK : E_INVALIDARG;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_nCharacters(long* aNCharacters)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNCharacters)
+ return E_INVALIDARG;
+ *aNCharacters = 0;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ *aNCharacters = textAcc->CharacterCount();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex,
+ enum IA2ScrollType aScrollType)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidRange(aStartIndex, aEndIndex))
+ return E_INVALIDARG;
+
+ textAcc->ScrollSubstringTo(aStartIndex, aEndIndex, aScrollType);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::scrollSubstringToPoint(long aStartIndex, long aEndIndex,
+ enum IA2CoordinateType aCoordType,
+ long aX, long aY)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
+ nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
+ nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+
+ MOZ_ASSERT(!HyperTextProxyFor(this));
+
+ HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+ if (textAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidRange(aStartIndex, aEndIndex))
+ return E_INVALIDARG;
+
+ textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex,
+ geckoCoordType, aX, aY);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_newText(IA2TextSegment *aNewText)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ return GetModifiedText(true, aNewText);
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_oldText(IA2TextSegment *aOldText)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ return GetModifiedText(false, aOldText);
+
+ A11Y_TRYBLOCK_END
+}
+
+// ia2AccessibleText
+
+HRESULT
+ia2AccessibleText::GetModifiedText(bool aGetInsertedText,
+ IA2TextSegment *aText)
+{
+ if (!aText)
+ return E_INVALIDARG;
+
+ if (!sLastTextChangeAcc)
+ return S_OK;
+
+ if (aGetInsertedText != sLastTextChangeWasInsert)
+ return S_OK;
+
+ if (sLastTextChangeAcc != this)
+ return S_OK;
+
+ aText->start = sLastTextChangeStart;
+ aText->end = sLastTextChangeEnd;
+
+ if (sLastTextChangeString->IsEmpty())
+ return S_FALSE;
+
+ aText->text = ::SysAllocStringLen(sLastTextChangeString->get(), sLastTextChangeString->Length());
+ return aText->text ? S_OK : E_OUTOFMEMORY;
+}
+
+AccessibleTextBoundary
+ia2AccessibleText::GetGeckoTextBoundary(enum IA2TextBoundaryType aBoundaryType)
+{
+ switch (aBoundaryType) {
+ case IA2_TEXT_BOUNDARY_CHAR:
+ return nsIAccessibleText::BOUNDARY_CHAR;
+ case IA2_TEXT_BOUNDARY_WORD:
+ return nsIAccessibleText::BOUNDARY_WORD_START;
+ case IA2_TEXT_BOUNDARY_LINE:
+ return nsIAccessibleText::BOUNDARY_LINE_START;
+ //case IA2_TEXT_BOUNDARY_SENTENCE:
+ //case IA2_TEXT_BOUNDARY_PARAGRAPH:
+ // XXX: not implemented
+ default:
+ return -1;
+ }
+}
+
+void
+ia2AccessibleText::InitTextChangeData()
+{
+ ClearOnShutdown(&sLastTextChangeAcc);
+ ClearOnShutdown(&sLastTextChangeString);
+}
+
+void
+ia2AccessibleText::UpdateTextChangeData(HyperTextAccessibleWrap* aAcc,
+ bool aInsert, const nsString& aStr,
+ int32_t aStart, uint32_t aLen)
+{
+ if (!sLastTextChangeString)
+ sLastTextChangeString = new nsString();
+
+ sLastTextChangeAcc = aAcc;
+ sLastTextChangeStart = aStart;
+ sLastTextChangeEnd = aStart + aLen;
+ sLastTextChangeWasInsert = aInsert;
+ *sLastTextChangeString = aStr;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleText.h b/accessible/windows/ia2/ia2AccessibleText.h
new file mode 100644
index 000000000..a513e44a2
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleText.h
@@ -0,0 +1,275 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _ACCESSIBLE_TEXT_H
+#define _ACCESSIBLE_TEXT_H
+
+#include "nsIAccessibleText.h"
+
+#include "AccessibleText.h"
+
+namespace mozilla {
+namespace a11y {
+class HyperTextAccessibleWrap;
+
+class ia2AccessibleText: public IAccessibleText
+{
+public:
+
+ // IAccessibleText
+ virtual HRESULT STDMETHODCALLTYPE addSelection(
+ /* [in] */ long startOffset,
+ /* [in] */ long endOffset);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_attributes(
+ /* [in] */ long offset,
+ /* [out] */ long *startOffset,
+ /* [out] */ long *endOffset,
+ /* [retval][out] */ BSTR *textAttributes);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_caretOffset(
+ /* [retval][out] */ long *offset);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_characterExtents(
+ /* [in] */ long offset,
+ /* [in] */ enum IA2CoordinateType coordType,
+ /* [out] */ long *x,
+ /* [out] */ long *y,
+ /* [out] */ long *width,
+ /* [retval][out] */ long *height);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelections(
+ /* [retval][out] */ long *nSelections);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_offsetAtPoint(
+ /* [in] */ long x,
+ /* [in] */ long y,
+ /* [in] */ enum IA2CoordinateType coordType,
+ /* [retval][out] */ long *offset);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selection(
+ /* [in] */ long selectionIndex,
+ /* [out] */ long *startOffset,
+ /* [retval][out] */ long *endOffset);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_text(
+ /* [in] */ long startOffset,
+ /* [in] */ long endOffset,
+ /* [retval][out] */ BSTR *text);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_textBeforeOffset(
+ /* [in] */ long offset,
+ /* [in] */ enum IA2TextBoundaryType boundaryType,
+ /* [out] */ long *startOffset,
+ /* [out] */ long *endOffset,
+ /* [retval][out] */ BSTR *text);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_textAfterOffset(
+ /* [in] */ long offset,
+ /* [in] */ enum IA2TextBoundaryType boundaryType,
+ /* [out] */ long *startOffset,
+ /* [out] */ long *endOffset,
+ /* [retval][out] */ BSTR *text);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_textAtOffset(
+ /* [in] */ long offset,
+ /* [in] */ enum IA2TextBoundaryType boundaryType,
+ /* [out] */ long *startOffset,
+ /* [out] */ long *endOffset,
+ /* [retval][out] */ BSTR *text);
+
+ virtual HRESULT STDMETHODCALLTYPE removeSelection(
+ /* [in] */ long selectionIndex);
+
+ virtual HRESULT STDMETHODCALLTYPE setCaretOffset(
+ /* [in] */ long offset);
+
+ virtual HRESULT STDMETHODCALLTYPE setSelection(
+ /* [in] */ long selectionIndex,
+ /* [in] */ long startOffset,
+ /* [in] */ long endOffset);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nCharacters(
+ /* [retval][out] */ long *nCharacters);
+
+ virtual HRESULT STDMETHODCALLTYPE scrollSubstringTo(
+ /* [in] */ long startIndex,
+ /* [in] */ long endIndex,
+ /* [in] */ enum IA2ScrollType scrollType);
+
+ virtual HRESULT STDMETHODCALLTYPE scrollSubstringToPoint(
+ /* [in] */ long startIndex,
+ /* [in] */ long endIndex,
+ /* [in] */ enum IA2CoordinateType coordinateType,
+ /* [in] */ long x,
+ /* [in] */ long y);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_newText(
+ /* [retval][out] */ IA2TextSegment *newText);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_oldText(
+ /* [retval][out] */ IA2TextSegment *oldText);
+
+ static void InitTextChangeData();
+ static void UpdateTextChangeData(HyperTextAccessibleWrap* aAcc, bool aInsert,
+ const nsString& aStr, int32_t aStart,
+ uint32_t aLen);
+
+protected:
+ static StaticRefPtr<HyperTextAccessibleWrap> sLastTextChangeAcc;
+ static StaticAutoPtr<nsString> sLastTextChangeString;
+ static bool sLastTextChangeWasInsert;
+ static uint32_t sLastTextChangeStart;
+ static uint32_t sLastTextChangeEnd;
+
+private:
+ HRESULT GetModifiedText(bool aGetInsertedText, IA2TextSegment *aNewText);
+ AccessibleTextBoundary GetGeckoTextBoundary(enum IA2TextBoundaryType coordinateType);
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+
+#define FORWARD_IACCESSIBLETEXT(Class) \
+virtual HRESULT STDMETHODCALLTYPE addSelection(long startOffset, \
+ long endOffset) \
+{ \
+ return Class::addSelection(startOffset, endOffset); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_attributes(long offset, \
+ long *startOffset, \
+ long *endOffset, \
+ BSTR *textAttributes) \
+{ \
+ return Class::get_attributes(offset, startOffset, endOffset, textAttributes);\
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_caretOffset(long *offset) \
+{ \
+ return Class::get_caretOffset(offset); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_characterExtents(long offset, \
+ enum IA2CoordinateType coordType,\
+ long *x, \
+ long *y, \
+ long *width, \
+ long *height) \
+{ \
+ return Class::get_characterExtents(offset, coordType, x, y, width, height); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_nSelections(long *nSelections) \
+{ \
+ return Class::get_nSelections(nSelections); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_offsetAtPoint(long x, \
+ long y, \
+ enum IA2CoordinateType coordType,\
+ long *offset) \
+{ \
+ return Class::get_offsetAtPoint(x, y, coordType, offset); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_selection(long selectionIndex, \
+ long *startOffset, \
+ long *endOffset) \
+{ \
+ return Class::get_selection(selectionIndex, startOffset, endOffset); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_text(long startOffset, \
+ long endOffset, \
+ BSTR *text) \
+{ \
+ return Class::get_text(startOffset, endOffset, text); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_textBeforeOffset(long offset, \
+ enum IA2TextBoundaryType boundaryType,\
+ long *startOffset, \
+ long *endOffset, \
+ BSTR *text) \
+{ \
+ return Class::get_textBeforeOffset(offset, boundaryType, \
+ startOffset, endOffset, text); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_textAfterOffset(long offset, \
+ enum IA2TextBoundaryType boundaryType,\
+ long *startOffset, \
+ long *endOffset, \
+ BSTR *text) \
+{ \
+ return Class::get_textAfterOffset(offset, boundaryType, \
+ startOffset, endOffset, text); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_textAtOffset(long offset, \
+ enum IA2TextBoundaryType boundaryType,\
+ long *startOffset, \
+ long *endOffset, \
+ BSTR *text) \
+{ \
+ return Class::get_textAtOffset(offset, boundaryType, \
+ startOffset, endOffset, text); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE removeSelection(long selectionIndex) \
+{ \
+ return Class::removeSelection(selectionIndex); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE setCaretOffset(long offset) \
+{ \
+ return Class::setCaretOffset(offset); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE setSelection(long selectionIndex, \
+ long startOffset, \
+ long endOffset) \
+{ \
+ return Class::setSelection(selectionIndex, startOffset, endOffset); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_nCharacters(long *nCharacters) \
+{ \
+ return Class::get_nCharacters(nCharacters); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE scrollSubstringTo(long startIndex, \
+ long endIndex, \
+ enum IA2ScrollType scrollType)\
+{ \
+ return Class::scrollSubstringTo(startIndex, endIndex, scrollType); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE scrollSubstringToPoint(long startIndex, \
+ long endIndex, \
+ enum IA2CoordinateType coordinateType,\
+ long x, \
+ long y) \
+{ \
+ return Class::scrollSubstringToPoint(startIndex, endIndex, \
+ coordinateType, x, y); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_newText(IA2TextSegment *newText) \
+{ \
+ return Class::get_newText(newText); \
+} \
+ \
+virtual HRESULT STDMETHODCALLTYPE get_oldText(IA2TextSegment *oldText) \
+{ \
+ return Class::get_oldText(oldText); \
+} \
+
+#endif
+
diff --git a/accessible/windows/ia2/ia2AccessibleValue.cpp b/accessible/windows/ia2/ia2AccessibleValue.cpp
new file mode 100644
index 000000000..e33442295
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleValue.cpp
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ia2AccessibleValue.h"
+
+#include "AccessibleValue_i.c"
+
+#include "AccessibleWrap.h"
+#include "Accessible-inl.h"
+#include "IUnknownImpl.h"
+
+#include "mozilla/FloatingPoint.h"
+
+using namespace mozilla::a11y;
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleValue::QueryInterface(REFIID iid, void** ppv)
+{
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleValue == iid) {
+ AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
+ if (valueAcc->HasNumericValue()) {
+ *ppv = static_cast<IAccessibleValue*>(this);
+ valueAcc->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+ return E_NOINTERFACE;
+}
+
+// IAccessibleValue
+
+STDMETHODIMP
+ia2AccessibleValue::get_currentValue(VARIANT* aCurrentValue)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aCurrentValue)
+ return E_INVALIDARG;
+
+ VariantInit(aCurrentValue);
+
+ AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
+ double currentValue;
+ MOZ_ASSERT(!valueAcc->IsProxy());
+ if (valueAcc->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ currentValue = valueAcc->CurValue();
+
+ if (IsNaN(currentValue))
+ return S_FALSE;
+
+ aCurrentValue->vt = VT_R8;
+ aCurrentValue->dblVal = currentValue;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleValue::setCurrentValue(VARIANT aValue)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (aValue.vt != VT_R8)
+ return E_INVALIDARG;
+
+ AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
+ MOZ_ASSERT(!valueAcc->IsProxy());
+
+ if (valueAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ return valueAcc->SetCurValue(aValue.dblVal) ? S_OK : E_FAIL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleValue::get_maximumValue(VARIANT* aMaximumValue)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aMaximumValue)
+ return E_INVALIDARG;
+
+ VariantInit(aMaximumValue);
+
+ AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
+ double maximumValue;
+ MOZ_ASSERT(!valueAcc->IsProxy());
+ if (valueAcc->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ maximumValue = valueAcc->MaxValue();
+
+ if (IsNaN(maximumValue))
+ return S_FALSE;
+
+ aMaximumValue->vt = VT_R8;
+ aMaximumValue->dblVal = maximumValue;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ia2AccessibleValue::get_minimumValue(VARIANT* aMinimumValue)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aMinimumValue)
+ return E_INVALIDARG;
+
+ VariantInit(aMinimumValue);
+
+ AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
+ double minimumValue;
+ MOZ_ASSERT(!valueAcc->IsProxy());
+ if (valueAcc->IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ minimumValue = valueAcc->MinValue();
+
+ if (IsNaN(minimumValue))
+ return S_FALSE;
+
+ aMinimumValue->vt = VT_R8;
+ aMinimumValue->dblVal = minimumValue;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
diff --git a/accessible/windows/ia2/ia2AccessibleValue.h b/accessible/windows/ia2/ia2AccessibleValue.h
new file mode 100644
index 000000000..97ce5ea59
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleValue.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _ACCESSIBLE_VALUE_H
+#define _ACCESSIBLE_VALUE_H
+
+#include "AccessibleValue.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ia2AccessibleValue: public IAccessibleValue
+{
+public:
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID, void**);
+
+ // IAccessibleValue
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_currentValue(
+ /* [retval][out] */ VARIANT *currentValue);
+
+ virtual HRESULT STDMETHODCALLTYPE setCurrentValue(
+ /* [in] */ VARIANT value);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_maximumValue(
+ /* [retval][out] */ VARIANT *maximumValue);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_minimumValue(
+ /* [retval][out] */ VARIANT *minimumValue);
+
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/moz.build b/accessible/windows/ia2/moz.build
new file mode 100644
index 000000000..443e87663
--- /dev/null
+++ b/accessible/windows/ia2/moz.build
@@ -0,0 +1,58 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS += [
+ 'ia2Accessible.h',
+ 'ia2AccessibleAction.h',
+ 'ia2AccessibleComponent.h',
+ 'ia2AccessibleEditableText.h',
+ 'ia2AccessibleHyperlink.h',
+ 'ia2AccessibleHypertext.h',
+ 'ia2AccessibleText.h',
+ 'ia2AccessibleValue.h',
+]
+
+UNIFIED_SOURCES += [
+ 'ia2Accessible.cpp',
+ 'ia2AccessibleAction.cpp',
+ 'ia2AccessibleComponent.cpp',
+ 'ia2AccessibleEditableText.cpp',
+ 'ia2AccessibleHyperlink.cpp',
+ 'ia2AccessibleHypertext.cpp',
+ 'ia2AccessibleImage.cpp',
+ 'ia2AccessibleRelation.cpp',
+ 'ia2AccessibleText.cpp',
+ 'ia2AccessibleValue.cpp',
+]
+
+# These files cannot be built in unified mode because they both include
+# AccessibleTable2_i.c.
+SOURCES += [
+ 'ia2AccessibleTable.cpp',
+ 'ia2AccessibleTableCell.cpp',
+]
+
+LOCAL_INCLUDES += [
+ '/accessible/base',
+ '/accessible/generic',
+ '/accessible/html',
+ '/accessible/windows',
+ '/accessible/windows/msaa',
+ '/accessible/xpcom',
+ '/accessible/xul',
+]
+
+FINAL_LIBRARY = 'xul'
+
+# The Windows MIDL code generator creates things like:
+#
+# #endif !_MIDL_USE_GUIDDEF_
+#
+# which clang-cl complains about. MSVC doesn't, so turn this warning off.
+if CONFIG['CLANG_CL']:
+ CXXFLAGS += ['-Wno-extra-tokens']
+
+include('/ipc/chromium/chromium-config.mozbuild')
diff --git a/accessible/windows/moz.build b/accessible/windows/moz.build
new file mode 100644
index 000000000..4bfa4f330
--- /dev/null
+++ b/accessible/windows/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += ['msaa', 'ia2', 'sdn', 'uia']
+
diff --git a/accessible/windows/msaa/ARIAGridAccessibleWrap.cpp b/accessible/windows/msaa/ARIAGridAccessibleWrap.cpp
new file mode 100644
index 000000000..04f7c112f
--- /dev/null
+++ b/accessible/windows/msaa/ARIAGridAccessibleWrap.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ARIAGridAccessibleWrap.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// ARIAGridAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(ARIAGridAccessibleWrap,
+ ARIAGridAccessible)
+
+IMPL_IUNKNOWN_INHERITED1(ARIAGridAccessibleWrap,
+ AccessibleWrap,
+ ia2AccessibleTable)
+
+void
+ARIAGridAccessibleWrap::Shutdown()
+{
+ ia2AccessibleTable::mTable = nullptr;
+ ARIAGridAccessible::Shutdown();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ARIAGridCellAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(ARIAGridCellAccessibleWrap,
+ ARIAGridCellAccessible)
+
+IMPL_IUNKNOWN_INHERITED1(ARIAGridCellAccessibleWrap,
+ HyperTextAccessibleWrap,
+ ia2AccessibleTableCell)
+
+void
+ARIAGridCellAccessibleWrap::Shutdown()
+{
+ ia2AccessibleTableCell::mTableCell = nullptr;
+ ARIAGridCellAccessible::Shutdown();
+}
diff --git a/accessible/windows/msaa/ARIAGridAccessibleWrap.h b/accessible/windows/msaa/ARIAGridAccessibleWrap.h
new file mode 100644
index 000000000..b03cc349f
--- /dev/null
+++ b/accessible/windows/msaa/ARIAGridAccessibleWrap.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H
+#define MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H
+
+#include "ARIAGridAccessible.h"
+#include "ia2AccessibleTable.h"
+#include "ia2AccessibleTableCell.h"
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * IA2 wrapper class for ARIAGridAccessible implementing IAccessibleTable and
+ * IAccessibleTable2 interfaces.
+ */
+class ARIAGridAccessibleWrap : public ARIAGridAccessible,
+ public ia2AccessibleTable
+{
+ ~ARIAGridAccessibleWrap() {}
+
+public:
+ ARIAGridAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ ARIAGridAccessible(aContent, aDoc), ia2AccessibleTable(this) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ virtual void Shutdown() override;
+};
+
+/**
+ * IA2 wrapper class for ARIAGridCellAccessible implementing
+ * IAccessibleTableCell interface.
+ */
+class ARIAGridCellAccessibleWrap : public ARIAGridCellAccessible,
+ public ia2AccessibleTableCell
+{
+ ~ARIAGridCellAccessibleWrap() {}
+
+public:
+ ARIAGridCellAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ ARIAGridCellAccessible(aContent, aDoc), ia2AccessibleTableCell(this) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ virtual void Shutdown() override;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/msaa/AccessibleWrap.cpp b/accessible/windows/msaa/AccessibleWrap.cpp
new file mode 100644
index 000000000..6112c370a
--- /dev/null
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -0,0 +1,1686 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AccessibleWrap.h"
+#include "Accessible-inl.h"
+
+#include "Compatibility.h"
+#include "DocAccessible-inl.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/a11y/DocAccessibleChild.h"
+#include "mozilla/a11y/DocAccessibleParent.h"
+#include "EnumVariant.h"
+#include "nsAccUtils.h"
+#include "nsCoreUtils.h"
+#include "nsIAccessibleEvent.h"
+#include "nsWinUtils.h"
+#include "mozilla/a11y/ProxyAccessible.h"
+#include "ProxyWrappers.h"
+#include "ServiceProvider.h"
+#include "Relation.h"
+#include "Role.h"
+#include "RootAccessible.h"
+#include "sdnAccessible.h"
+#include "States.h"
+
+#ifdef A11Y_LOG
+#include "Logging.h"
+#endif
+
+#include "nsIMutableArray.h"
+#include "nsIFrame.h"
+#include "nsIScrollableFrame.h"
+#include "mozilla/dom/NodeInfo.h"
+#include "nsIServiceManager.h"
+#include "nsNameSpaceManager.h"
+#include "nsTextFormatter.h"
+#include "nsView.h"
+#include "nsViewManager.h"
+#include "nsEventMap.h"
+#include "nsArrayUtils.h"
+#include "mozilla/Preferences.h"
+#include "nsIXULRuntime.h"
+
+#include "oleacc.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+const uint32_t USE_ROLE_STRING = 0;
+
+/* For documentation of the accessibility architecture,
+ * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
+ */
+
+//#define DEBUG_LEAKS
+
+#ifdef DEBUG_LEAKS
+static gAccessibles = 0;
+#endif
+
+MsaaIdGenerator AccessibleWrap::sIDGen;
+
+static const VARIANT kVarChildIdSelf = {VT_I4};
+
+static const int32_t kIEnumVariantDisconnected = -1;
+
+////////////////////////////////////////////////////////////////////////////////
+// AccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+AccessibleWrap::AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ Accessible(aContent, aDoc)
+ , mID(kNoID)
+{
+}
+
+AccessibleWrap::~AccessibleWrap()
+{
+ if (mID != kNoID) {
+ sIDGen.ReleaseID(this);
+ }
+}
+
+ITypeInfo* AccessibleWrap::gTypeInfo = nullptr;
+
+NS_IMPL_ISUPPORTS_INHERITED0(AccessibleWrap, Accessible)
+
+void
+AccessibleWrap::Shutdown()
+{
+ if (mID != kNoID) {
+ auto doc = static_cast<DocAccessibleWrap*>(mDoc.get());
+ MOZ_ASSERT(doc);
+ if (doc) {
+ doc->RemoveID(mID);
+ mID = kNoID;
+ }
+ }
+
+ Accessible::Shutdown();
+}
+
+//-----------------------------------------------------
+// IUnknown interface methods - see iunknown.h for documentation
+//-----------------------------------------------------
+
+// Microsoft COM QueryInterface
+STDMETHODIMP
+AccessibleWrap::QueryInterface(REFIID iid, void** ppv)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IUnknown == iid)
+ *ppv = static_cast<IAccessible*>(this);
+ else if (IID_IDispatch == iid || IID_IAccessible == iid)
+ *ppv = static_cast<IAccessible*>(this);
+ else if (IID_IEnumVARIANT == iid && !IsProxy()) {
+ // Don't support this interface for leaf elements.
+ if (!HasChildren() || nsAccUtils::MustPrune(this))
+ return E_NOINTERFACE;
+
+ *ppv = static_cast<IEnumVARIANT*>(new ChildrenEnumVariant(this));
+ } else if (IID_IServiceProvider == iid)
+ *ppv = new ServiceProvider(this);
+ else if (IID_ISimpleDOMNode == iid && !IsProxy()) {
+ if (IsDefunct() || (!HasOwnContent() && !IsDoc()))
+ return E_NOINTERFACE;
+
+ *ppv = static_cast<ISimpleDOMNode*>(new sdnAccessible(GetNode()));
+ }
+
+ if (nullptr == *ppv) {
+ HRESULT hr = ia2Accessible::QueryInterface(iid, ppv);
+ if (SUCCEEDED(hr))
+ return hr;
+ }
+
+ if (nullptr == *ppv && !IsProxy()) {
+ HRESULT hr = ia2AccessibleComponent::QueryInterface(iid, ppv);
+ if (SUCCEEDED(hr))
+ return hr;
+ }
+
+ if (nullptr == *ppv) {
+ HRESULT hr = ia2AccessibleHyperlink::QueryInterface(iid, ppv);
+ if (SUCCEEDED(hr))
+ return hr;
+ }
+
+ if (nullptr == *ppv && !IsProxy()) {
+ HRESULT hr = ia2AccessibleValue::QueryInterface(iid, ppv);
+ if (SUCCEEDED(hr))
+ return hr;
+ }
+
+ if (nullptr == *ppv)
+ return E_NOINTERFACE;
+
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+//-----------------------------------------------------
+// IAccessible methods
+//-----------------------------------------------------
+
+STDMETHODIMP
+AccessibleWrap::get_accParent( IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!ppdispParent)
+ return E_INVALIDARG;
+
+ *ppdispParent = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ DocAccessible* doc = AsDoc();
+ if (doc) {
+ // Return window system accessible object for root document and tab document
+ // accessibles.
+ if (!doc->ParentDocument() ||
+ (nsWinUtils::IsWindowEmulationStarted() &&
+ nsCoreUtils::IsTabDocument(doc->DocumentNode()))) {
+ HWND hwnd = static_cast<HWND>(doc->GetNativeWindow());
+ if (hwnd && SUCCEEDED(::AccessibleObjectFromWindow(hwnd, OBJID_WINDOW,
+ IID_IAccessible,
+ (void**)ppdispParent))) {
+ return S_OK;
+ }
+ }
+ }
+
+ Accessible* xpParentAcc = Parent();
+ if (!xpParentAcc)
+ return S_FALSE;
+
+ *ppdispParent = NativeAccessible(xpParentAcc);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accChildCount( long __RPC_FAR *pcountChildren)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pcountChildren)
+ return E_INVALIDARG;
+
+ *pcountChildren = 0;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (nsAccUtils::MustPrune(this))
+ return S_OK;
+
+ *pcountChildren = ChildCount();
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accChild(
+ /* [in] */ VARIANT varChild,
+ /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!ppdispChild)
+ return E_INVALIDARG;
+
+ *ppdispChild = nullptr;
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ // IAccessible::accChild is used to return this accessible or child accessible
+ // at the given index or to get an accessible by child ID in the case of
+ // document accessible.
+ // The getting an accessible by child ID is used by AccessibleObjectFromEvent()
+ // called by AT when AT handles our MSAA event.
+ bool isDefunct = false;
+ RefPtr<IAccessible> child = GetIAccessibleFor(varChild, &isDefunct);
+ if (!child) {
+ return E_INVALIDARG;
+ }
+
+ if (isDefunct) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ child.forget(ppdispChild);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+/**
+ * This function is a helper for implementing IAccessible methods that accept
+ * a Child ID as a parameter. If the child ID is CHILDID_SELF, the function
+ * returns S_OK but a null *aOutInterface. Otherwise, *aOutInterface points
+ * to the resolved IAccessible.
+ *
+ * The CHILDID_SELF case is special because in that case we actually execute
+ * the implementation of the IAccessible method, whereas in the non-self case,
+ * we delegate the method call to that object for execution.
+ *
+ * A sample invocation of this would look like:
+ *
+ * RefPtr<IAccessible> accessible;
+ * HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ * if (FAILED(hr)) {
+ * return hr;
+ * }
+ *
+ * if (accessible) {
+ * return accessible->get_accFoo(kVarChildIdSelf, pszName);
+ * }
+ *
+ * // Implementation for CHILDID_SELF case goes here
+ */
+HRESULT
+AccessibleWrap::ResolveChild(const VARIANT& aVarChild,
+ IAccessible** aOutInterface)
+{
+ MOZ_ASSERT(aOutInterface);
+ *aOutInterface = nullptr;
+
+ if (aVarChild.vt != VT_I4) {
+ return E_INVALIDARG;
+ }
+
+ if (IsDefunct()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (aVarChild.lVal == CHILDID_SELF) {
+ return S_OK;
+ }
+
+ bool isDefunct = false;
+ RefPtr<IAccessible> accessible = GetIAccessibleFor(aVarChild, &isDefunct);
+ if (!accessible) {
+ return E_INVALIDARG;
+ }
+
+ if (isDefunct) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ accessible.forget(aOutInterface);
+ return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accName(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszName)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pszName || varChild.vt != VT_I4)
+ return E_INVALIDARG;
+
+ *pszName = nullptr;
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->get_accName(kVarChildIdSelf, pszName);
+ }
+
+ nsAutoString name;
+ Name(name);
+
+ // The name was not provided, e.g. no alt attribute for an image. A screen
+ // reader may choose to invent its own accessible name, e.g. from an image src
+ // attribute. Refer to eNoNameOnPurpose return value.
+ if (name.IsVoid())
+ return S_FALSE;
+
+ *pszName = ::SysAllocStringLen(name.get(), name.Length());
+ if (!*pszName)
+ return E_OUTOFMEMORY;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+
+STDMETHODIMP
+AccessibleWrap::get_accValue(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszValue)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pszValue)
+ return E_INVALIDARG;
+
+ *pszValue = nullptr;
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->get_accValue(kVarChildIdSelf, pszValue);
+ }
+
+ nsAutoString value;
+ Value(value);
+
+ // See bug 438784: need to expose URL on doc's value attribute. For this,
+ // reverting part of fix for bug 425693 to make this MSAA method behave
+ // IAccessible2-style.
+ if (value.IsEmpty())
+ return S_FALSE;
+
+ *pszValue = ::SysAllocStringLen(value.get(), value.Length());
+ if (!*pszValue)
+ return E_OUTOFMEMORY;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accDescription(VARIANT varChild,
+ BSTR __RPC_FAR *pszDescription)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pszDescription)
+ return E_INVALIDARG;
+
+ *pszDescription = nullptr;
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->get_accDescription(kVarChildIdSelf, pszDescription);
+ }
+
+ nsAutoString description;
+ Description(description);
+
+ *pszDescription = ::SysAllocStringLen(description.get(),
+ description.Length());
+ return *pszDescription ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accRole(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarRole)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pvarRole)
+ return E_INVALIDARG;
+
+ VariantInit(pvarRole);
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->get_accRole(kVarChildIdSelf, pvarRole);
+ }
+
+ a11y::role geckoRole;
+#ifdef DEBUG
+ NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(this),
+ "Does not support Text when it should");
+#endif
+
+ geckoRole = Role();
+
+ uint32_t msaaRole = 0;
+
+#define ROLE(_geckoRole, stringRole, atkRole, macRole, \
+ _msaaRole, ia2Role, nameRule) \
+ case roles::_geckoRole: \
+ msaaRole = _msaaRole; \
+ break;
+
+ switch (geckoRole) {
+#include "RoleMap.h"
+ default:
+ MOZ_CRASH("Unknown role.");
+ }
+
+#undef ROLE
+
+ // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call the MSAA role
+ // a ROLE_OUTLINEITEM for consistency and compatibility.
+ // We need this because ARIA has a role of "row" for both grid and treegrid
+ if (geckoRole == roles::ROW) {
+ Accessible* xpParent = Parent();
+ if (xpParent && xpParent->Role() == roles::TREE_TABLE)
+ msaaRole = ROLE_SYSTEM_OUTLINEITEM;
+ }
+
+ // -- Try enumerated role
+ if (msaaRole != USE_ROLE_STRING) {
+ pvarRole->vt = VT_I4;
+ pvarRole->lVal = msaaRole; // Normal enumerated role
+ return S_OK;
+ }
+
+ // -- Try BSTR role
+ // Could not map to known enumerated MSAA role like ROLE_BUTTON
+ // Use BSTR role to expose role attribute or tag name + namespace
+ nsIContent *content = GetContent();
+ if (!content)
+ return E_FAIL;
+
+ if (content->IsElement()) {
+ nsAutoString roleString;
+ if (msaaRole != ROLE_SYSTEM_CLIENT &&
+ !content->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roleString)) {
+ nsIDocument * document = content->GetUncomposedDoc();
+ if (!document)
+ return E_FAIL;
+
+ dom::NodeInfo *nodeInfo = content->NodeInfo();
+ nodeInfo->GetName(roleString);
+
+ // Only append name space if different from that of current document.
+ if (!nodeInfo->NamespaceEquals(document->GetDefaultNamespaceID())) {
+ nsAutoString nameSpaceURI;
+ nodeInfo->GetNamespaceURI(nameSpaceURI);
+ roleString += NS_LITERAL_STRING(", ") + nameSpaceURI;
+ }
+ }
+
+ if (!roleString.IsEmpty()) {
+ pvarRole->vt = VT_BSTR;
+ pvarRole->bstrVal = ::SysAllocString(roleString.get());
+ return S_OK;
+ }
+ }
+
+ return E_FAIL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accState(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarState)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pvarState)
+ return E_INVALIDARG;
+
+ VariantInit(pvarState);
+ pvarState->vt = VT_I4;
+ pvarState->lVal = 0;
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->get_accState(kVarChildIdSelf, pvarState);
+ }
+
+ // MSAA only has 31 states and the lowest 31 bits of our state bit mask
+ // are the same states as MSAA.
+ // Note: we map the following Gecko states to different MSAA states:
+ // REQUIRED -> ALERT_LOW
+ // ALERT -> ALERT_MEDIUM
+ // INVALID -> ALERT_HIGH
+ // CHECKABLE -> MARQUEED
+
+ uint64_t state = State();
+
+ uint32_t msaaState = 0;
+ nsAccUtils::To32States(state, &msaaState, nullptr);
+ pvarState->lVal = msaaState;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+
+STDMETHODIMP
+AccessibleWrap::get_accHelp(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszHelp)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pszHelp)
+ return E_INVALIDARG;
+
+ *pszHelp = nullptr;
+ return S_FALSE;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accHelpTopic(
+ /* [out] */ BSTR __RPC_FAR *pszHelpFile,
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ long __RPC_FAR *pidTopic)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pszHelpFile || !pidTopic)
+ return E_INVALIDARG;
+
+ *pszHelpFile = nullptr;
+ *pidTopic = 0;
+ return S_FALSE;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accKeyboardShortcut(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszKeyboardShortcut)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pszKeyboardShortcut)
+ return E_INVALIDARG;
+ *pszKeyboardShortcut = nullptr;
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->get_accKeyboardShortcut(kVarChildIdSelf,
+ pszKeyboardShortcut);
+ }
+
+ KeyBinding keyBinding = AccessKey();
+ if (keyBinding.IsEmpty())
+ keyBinding = KeyboardShortcut();
+
+ nsAutoString shortcut;
+ keyBinding.ToString(shortcut);
+
+ *pszKeyboardShortcut = ::SysAllocStringLen(shortcut.get(),
+ shortcut.Length());
+ return *pszKeyboardShortcut ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accFocus(
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pvarChild)
+ return E_INVALIDARG;
+
+ VariantInit(pvarChild);
+
+ // VT_EMPTY: None. This object does not have the keyboard focus itself
+ // and does not contain a child that has the keyboard focus.
+ // VT_I4: lVal is CHILDID_SELF. The object itself has the keyboard focus.
+ // VT_I4: lVal contains the child ID of the child element with the keyboard focus.
+ // VT_DISPATCH: pdispVal member is the address of the IDispatch interface
+ // for the child object with the keyboard focus.
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ // Return the current IAccessible child that has focus
+ Accessible* focusedAccessible = FocusedChild();
+
+ if (focusedAccessible == this) {
+ pvarChild->vt = VT_I4;
+ pvarChild->lVal = CHILDID_SELF;
+ }
+ else if (focusedAccessible) {
+ pvarChild->vt = VT_DISPATCH;
+ pvarChild->pdispVal = NativeAccessible(focusedAccessible);
+ }
+ else {
+ pvarChild->vt = VT_EMPTY; // No focus or focus is not a child
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+/**
+ * This helper class implements IEnumVARIANT for a nsTArray containing
+ * accessible objects.
+ */
+class AccessibleEnumerator final : public IEnumVARIANT
+{
+public:
+ AccessibleEnumerator(const nsTArray<Accessible*>& aArray) :
+ mArray(aArray), mCurIndex(0) { }
+ AccessibleEnumerator(const AccessibleEnumerator& toCopy) :
+ mArray(toCopy.mArray), mCurIndex(toCopy.mCurIndex) { }
+ ~AccessibleEnumerator() { }
+
+ // IUnknown
+ DECL_IUNKNOWN
+
+ // IEnumVARIANT
+ STDMETHODIMP Next(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched);
+ STDMETHODIMP Skip(unsigned long celt);
+ STDMETHODIMP Reset()
+ {
+ mCurIndex = 0;
+ return S_OK;
+ }
+ STDMETHODIMP Clone(IEnumVARIANT FAR* FAR* ppenum);
+
+private:
+ nsTArray<Accessible*> mArray;
+ uint32_t mCurIndex;
+};
+
+STDMETHODIMP
+AccessibleEnumerator::QueryInterface(REFIID iid, void ** ppvObject)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (iid == IID_IEnumVARIANT) {
+ *ppvObject = static_cast<IEnumVARIANT*>(this);
+ AddRef();
+ return S_OK;
+ }
+ if (iid == IID_IUnknown) {
+ *ppvObject = static_cast<IUnknown*>(this);
+ AddRef();
+ return S_OK;
+ }
+
+ *ppvObject = nullptr;
+ return E_NOINTERFACE;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleEnumerator::Next(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ uint32_t length = mArray.Length();
+ HRESULT hr = S_OK;
+
+ // Can't get more elements than there are...
+ if (celt > length - mCurIndex) {
+ hr = S_FALSE;
+ celt = length - mCurIndex;
+ }
+
+ // Copy the elements of the array into rgvar.
+ for (uint32_t i = 0; i < celt; ++i, ++mCurIndex) {
+ rgvar[i].vt = VT_DISPATCH;
+ rgvar[i].pdispVal = AccessibleWrap::NativeAccessible(mArray[mCurIndex]);
+ }
+
+ if (pceltFetched)
+ *pceltFetched = celt;
+
+ return hr;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleEnumerator::Clone(IEnumVARIANT FAR* FAR* ppenum)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ *ppenum = new AccessibleEnumerator(*this);
+ if (!*ppenum)
+ return E_OUTOFMEMORY;
+ NS_ADDREF(*ppenum);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleEnumerator::Skip(unsigned long celt)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ uint32_t length = mArray.Length();
+ // Check if we can skip the requested number of elements
+ if (celt > length - mCurIndex) {
+ mCurIndex = length;
+ return S_FALSE;
+ }
+ mCurIndex += celt;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+/**
+ * This method is called when a client wants to know which children of a node
+ * are selected. Note that this method can only find selected children for
+ * accessible object which implement SelectAccessible.
+ *
+ * The VARIANT return value arguement is expected to either contain a single IAccessible
+ * or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT regardless of the number
+ * of children selected, unless there are none selected in which case we return an empty
+ * VARIANT.
+ *
+ * We get the selected options from the select's accessible object and wrap
+ * those in an AccessibleEnumerator which we then put in the return VARIANT.
+ *
+ * returns a VT_EMPTY VARIANT if:
+ * - there are no selected children for this object
+ * - the object is not the type that can have children selected
+ */
+STDMETHODIMP
+AccessibleWrap::get_accSelection(VARIANT __RPC_FAR *pvarChildren)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pvarChildren)
+ return E_INVALIDARG;
+
+ VariantInit(pvarChildren);
+ pvarChildren->vt = VT_EMPTY;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (IsSelect()) {
+ AutoTArray<Accessible*, 10> selectedItems;
+ SelectedItems(&selectedItems);
+
+ // 1) Create and initialize the enumeration
+ RefPtr<AccessibleEnumerator> pEnum = new AccessibleEnumerator(selectedItems);
+ pvarChildren->vt = VT_UNKNOWN; // this must be VT_UNKNOWN for an IEnumVARIANT
+ NS_ADDREF(pvarChildren->punkVal = pEnum);
+ }
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accDefaultAction(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszDefaultAction)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pszDefaultAction)
+ return E_INVALIDARG;
+
+ *pszDefaultAction = nullptr;
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->get_accDefaultAction(kVarChildIdSelf, pszDefaultAction);
+ }
+
+ nsAutoString defaultAction;
+ ActionNameAt(0, defaultAction);
+
+ *pszDefaultAction = ::SysAllocStringLen(defaultAction.get(),
+ defaultAction.Length());
+ return *pszDefaultAction ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::accSelect(
+ /* [in] */ long flagsSelect,
+ /* [optional][in] */ VARIANT varChild)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->accSelect(flagsSelect, kVarChildIdSelf);
+ }
+
+ if (flagsSelect & SELFLAG_TAKEFOCUS) {
+ if (XRE_IsContentProcess()) {
+ // In this case we might have been invoked while the IPC MessageChannel is
+ // waiting on a sync reply. We cannot dispatch additional IPC while that
+ // is happening, so we dispatch TakeFocus from the main thread to
+ // guarantee that we are outside any IPC.
+ nsCOMPtr<nsIRunnable> runnable =
+ mozilla::NewRunnableMethod(this, &Accessible::TakeFocus);
+ NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
+ return S_OK;
+ }
+ TakeFocus();
+ return S_OK;
+ }
+
+ if (flagsSelect & SELFLAG_TAKESELECTION) {
+ TakeSelection();
+ return S_OK;
+ }
+
+ if (flagsSelect & SELFLAG_ADDSELECTION) {
+ SetSelected(true);
+ return S_OK;
+ }
+
+ if (flagsSelect & SELFLAG_REMOVESELECTION) {
+ SetSelected(false);
+ return S_OK;
+ }
+
+ return E_FAIL;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::accLocation(
+ /* [out] */ long __RPC_FAR *pxLeft,
+ /* [out] */ long __RPC_FAR *pyTop,
+ /* [out] */ long __RPC_FAR *pcxWidth,
+ /* [out] */ long __RPC_FAR *pcyHeight,
+ /* [optional][in] */ VARIANT varChild)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pxLeft || !pyTop || !pcxWidth || !pcyHeight)
+ return E_INVALIDARG;
+
+ *pxLeft = 0;
+ *pyTop = 0;
+ *pcxWidth = 0;
+ *pcyHeight = 0;
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight,
+ kVarChildIdSelf);
+ }
+
+ nsIntRect rect = Bounds();
+
+ *pxLeft = rect.x;
+ *pyTop = rect.y;
+ *pcxWidth = rect.width;
+ *pcyHeight = rect.height;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::accNavigate(
+ /* [in] */ long navDir,
+ /* [optional][in] */ VARIANT varStart,
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pvarEndUpAt)
+ return E_INVALIDARG;
+
+ VariantInit(pvarEndUpAt);
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varStart, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->accNavigate(navDir, kVarChildIdSelf, pvarEndUpAt);
+ }
+
+ Accessible* navAccessible = nullptr;
+ Maybe<RelationType> xpRelation;
+
+#define RELATIONTYPE(geckoType, stringType, atkType, msaaType, ia2Type) \
+ case msaaType: \
+ xpRelation.emplace(RelationType::geckoType); \
+ break;
+
+ switch(navDir) {
+ case NAVDIR_FIRSTCHILD:
+ if (IsProxy()) {
+ if (!Proxy()->MustPruneChildren()) {
+ navAccessible = WrapperFor(Proxy()->FirstChild());
+ }
+ } else {
+ if (!nsAccUtils::MustPrune(this))
+ navAccessible = FirstChild();
+ }
+ break;
+ case NAVDIR_LASTCHILD:
+ if (IsProxy()) {
+ if (!Proxy()->MustPruneChildren()) {
+ navAccessible = WrapperFor(Proxy()->LastChild());
+ }
+ } else {
+ if (!nsAccUtils::MustPrune(this))
+ navAccessible = LastChild();
+ }
+ break;
+ case NAVDIR_NEXT:
+ navAccessible = IsProxy()
+ ? WrapperFor(Proxy()->NextSibling())
+ : NextSibling();
+ break;
+ case NAVDIR_PREVIOUS:
+ navAccessible = IsProxy()
+ ? WrapperFor(Proxy()->PrevSibling())
+ : PrevSibling();
+ break;
+ case NAVDIR_DOWN:
+ case NAVDIR_LEFT:
+ case NAVDIR_RIGHT:
+ case NAVDIR_UP:
+ return E_NOTIMPL;
+
+ // MSAA relationship extensions to accNavigate
+#include "RelationTypeMap.h"
+
+ default:
+ return E_INVALIDARG;
+ }
+
+#undef RELATIONTYPE
+
+ pvarEndUpAt->vt = VT_EMPTY;
+
+ if (xpRelation) {
+ Relation rel = RelationByType(*xpRelation);
+ navAccessible = rel.Next();
+ }
+
+ if (!navAccessible)
+ return E_FAIL;
+
+ pvarEndUpAt->pdispVal = NativeAccessible(navAccessible);
+ pvarEndUpAt->vt = VT_DISPATCH;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::accHitTest(
+ /* [in] */ long xLeft,
+ /* [in] */ long yTop,
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!pvarChild)
+ return E_INVALIDARG;
+
+ VariantInit(pvarChild);
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ Accessible* accessible = ChildAtPoint(xLeft, yTop, eDirectChild);
+
+ // if we got a child
+ if (accessible) {
+ // if the child is us
+ if (accessible == this) {
+ pvarChild->vt = VT_I4;
+ pvarChild->lVal = CHILDID_SELF;
+ } else { // its not create an Accessible for it.
+ pvarChild->vt = VT_DISPATCH;
+ pvarChild->pdispVal = NativeAccessible(accessible);
+ }
+ } else {
+ // no child at that point
+ pvarChild->vt = VT_EMPTY;
+ return S_FALSE;
+ }
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::accDoDefaultAction(
+ /* [optional][in] */ VARIANT varChild)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ RefPtr<IAccessible> accessible;
+ HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (accessible) {
+ return accessible->accDoDefaultAction(kVarChildIdSelf);
+ }
+
+ return DoAction(0) ? S_OK : E_INVALIDARG;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+AccessibleWrap::put_accName(
+ /* [optional][in] */ VARIANT varChild,
+ /* [in] */ BSTR szName)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+AccessibleWrap::put_accValue(
+ /* [optional][in] */ VARIANT varChild,
+ /* [in] */ BSTR szValue)
+{
+ return E_NOTIMPL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IDispatch
+
+STDMETHODIMP
+AccessibleWrap::GetTypeInfoCount(UINT *pctinfo)
+{
+ if (!pctinfo)
+ return E_INVALIDARG;
+
+ *pctinfo = 1;
+ return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
+{
+ if (!ppTInfo)
+ return E_INVALIDARG;
+
+ *ppTInfo = nullptr;
+
+ if (iTInfo != 0)
+ return DISP_E_BADINDEX;
+
+ ITypeInfo * typeInfo = GetTI(lcid);
+ if (!typeInfo)
+ return E_FAIL;
+
+ typeInfo->AddRef();
+ *ppTInfo = typeInfo;
+
+ return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames,
+ UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+ ITypeInfo *typeInfo = GetTI(lcid);
+ if (!typeInfo)
+ return E_FAIL;
+
+ HRESULT hr = DispGetIDsOfNames(typeInfo, rgszNames, cNames, rgDispId);
+ return hr;
+}
+
+STDMETHODIMP
+AccessibleWrap::Invoke(DISPID dispIdMember, REFIID riid,
+ LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
+ VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
+ UINT *puArgErr)
+{
+ ITypeInfo *typeInfo = GetTI(lcid);
+ if (!typeInfo)
+ return E_FAIL;
+
+ return typeInfo->Invoke(static_cast<IAccessible*>(this), dispIdMember,
+ wFlags, pDispParams, pVarResult, pExcepInfo,
+ puArgErr);
+}
+
+void
+AccessibleWrap::GetNativeInterface(void** aOutAccessible)
+{
+ *aOutAccessible = static_cast<IAccessible*>(this);
+ NS_ADDREF_THIS();
+}
+
+void
+AccessibleWrap::SetID(uint32_t aID)
+{
+ MOZ_ASSERT(XRE_IsParentProcess() && IsProxy());
+ mID = aID;
+}
+
+void
+AccessibleWrap::FireWinEvent(Accessible* aTarget, uint32_t aEventType)
+{
+ MOZ_ASSERT(XRE_IsParentProcess());
+ static_assert(sizeof(gWinEventMap)/sizeof(gWinEventMap[0]) == nsIAccessibleEvent::EVENT_LAST_ENTRY,
+ "MSAA event map skewed");
+
+ NS_ASSERTION(aEventType > 0 && aEventType < ArrayLength(gWinEventMap), "invalid event type");
+
+ uint32_t winEvent = gWinEventMap[aEventType];
+ if (!winEvent)
+ return;
+
+ int32_t childID = GetChildIDFor(aTarget);
+ if (!childID)
+ return; // Can't fire an event without a child ID
+
+ HWND hwnd = GetHWNDFor(aTarget);
+ if (!hwnd) {
+ return;
+ }
+
+ // Fire MSAA event for client area window.
+ ::NotifyWinEvent(winEvent, hwnd, OBJID_CLIENT, childID);
+
+ // JAWS announces collapsed combobox navigation based on focus events.
+ if (aEventType == nsIAccessibleEvent::EVENT_SELECTION &&
+ Compatibility::IsJAWS()) {
+ roles::Role role = aTarget->IsProxy() ? aTarget->Proxy()->Role() :
+ aTarget->Role();
+ if (role == roles::COMBOBOX_OPTION) {
+ ::NotifyWinEvent(EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, childID);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Accessible
+
+nsresult
+AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
+{
+ nsresult rv = Accessible::HandleAccEvent(aEvent);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (IPCAccessibilityActive()) {
+ return NS_OK;
+ }
+
+ uint32_t eventType = aEvent->GetEventType();
+
+ // Means we're not active.
+ NS_ENSURE_TRUE(!IsDefunct(), NS_ERROR_FAILURE);
+
+ Accessible* accessible = aEvent->GetAccessible();
+ if (!accessible)
+ return NS_OK;
+
+ if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED ||
+ eventType == nsIAccessibleEvent::EVENT_FOCUS) {
+ UpdateSystemCaretFor(accessible);
+ }
+
+ FireWinEvent(accessible, eventType);
+
+ return NS_OK;
+}
+
+DocProxyAccessibleWrap*
+AccessibleWrap::DocProxyWrapper() const
+{
+ MOZ_ASSERT(IsProxy());
+
+ ProxyAccessible* proxy = Proxy();
+ if (!proxy) {
+ return nullptr;
+ }
+
+ AccessibleWrap* acc = WrapperFor(proxy->Document());
+ MOZ_ASSERT(acc->IsDoc());
+
+ return static_cast<DocProxyAccessibleWrap*>(acc);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AccessibleWrap
+
+//------- Helper methods ---------
+
+int32_t
+AccessibleWrap::GetChildIDFor(Accessible* aAccessible)
+{
+ // A child ID of the window is required, when we use NotifyWinEvent,
+ // so that the 3rd party application can call back and get the IAccessible
+ // the event occurred on.
+
+ if (!aAccessible) {
+ return 0;
+ }
+
+ // Chrome should use mID which has been generated by the content process.
+ if (aAccessible->IsProxy()) {
+ const uint32_t id = static_cast<AccessibleWrap*>(aAccessible)->mID;
+ MOZ_ASSERT(id != kNoID);
+ return id;
+ }
+
+ if (!aAccessible->Document())
+ return 0;
+
+ uint32_t* id = & static_cast<AccessibleWrap*>(aAccessible)->mID;
+ if (*id != kNoID)
+ return *id;
+
+ *id = sIDGen.GetID();
+
+ MOZ_ASSERT(!aAccessible->IsProxy());
+ DocAccessibleWrap* doc =
+ static_cast<DocAccessibleWrap*>(aAccessible->Document());
+ doc->AddID(*id, static_cast<AccessibleWrap*>(aAccessible));
+
+ return *id;
+}
+
+HWND
+AccessibleWrap::GetHWNDFor(Accessible* aAccessible)
+{
+ if (!aAccessible) {
+ return nullptr;
+ }
+
+ if (XRE_IsContentProcess()) {
+ DocAccessible* doc = aAccessible->Document();
+ if (!doc) {
+ return nullptr;
+ }
+
+ DocAccessibleChild* ipcDoc = doc->IPCDoc();
+ if (!ipcDoc) {
+ return nullptr;
+ }
+
+ auto tab = static_cast<dom::TabChild*>(ipcDoc->Manager());
+ MOZ_ASSERT(tab);
+ return reinterpret_cast<HWND>(tab->GetNativeWindowHandle());
+ }
+
+ // Accessibles in child processes are said to have the HWND of the window
+ // their tab is within. Popups are always in the parent process, and so
+ // never proxied, which means this is basically correct.
+ if (aAccessible->IsProxy()) {
+ ProxyAccessible* proxy = aAccessible->Proxy();
+ if (!proxy) {
+ return nullptr;
+ }
+
+ Accessible* outerDoc = proxy->OuterDocOfRemoteBrowser();
+ NS_ASSERTION(outerDoc, "no outer doc for accessible remote tab!");
+ if (!outerDoc) {
+ return nullptr;
+ }
+
+ return GetHWNDFor(outerDoc);
+ }
+
+ DocAccessible* document = aAccessible->Document();
+ if(!document)
+ return nullptr;
+
+ // Popup lives in own windows, use its HWND until the popup window is
+ // hidden to make old JAWS versions work with collapsed comboboxes (see
+ // discussion in bug 379678).
+ nsIFrame* frame = aAccessible->GetFrame();
+ if (frame) {
+ nsIWidget* widget = frame->GetNearestWidget();
+ if (widget && widget->IsVisible()) {
+ nsIPresShell* shell = document->PresShell();
+ nsViewManager* vm = shell->GetViewManager();
+ if (vm) {
+ nsCOMPtr<nsIWidget> rootWidget;
+ vm->GetRootWidget(getter_AddRefs(rootWidget));
+ // Make sure the accessible belongs to popup. If not then use
+ // document HWND (which might be different from root widget in the
+ // case of window emulation).
+ if (rootWidget != widget)
+ return static_cast<HWND>(widget->GetNativeData(NS_NATIVE_WINDOW));
+ }
+ }
+ }
+
+ return static_cast<HWND>(document->GetNativeWindow());
+}
+
+IDispatch*
+AccessibleWrap::NativeAccessible(Accessible* aAccessible)
+{
+ if (!aAccessible) {
+ NS_WARNING("Not passing in an aAccessible");
+ return nullptr;
+ }
+
+ IAccessible* msaaAccessible = nullptr;
+ aAccessible->GetNativeInterface(reinterpret_cast<void**>(&msaaAccessible));
+ return static_cast<IDispatch*>(msaaAccessible);
+}
+
+static Accessible*
+GetAccessibleInSubtree(DocAccessible* aDoc, uint32_t aID)
+{
+ Accessible* child = static_cast<DocAccessibleWrap*>(aDoc)->GetAccessibleByID(aID);
+ if (child)
+ return child;
+
+ uint32_t childDocCount = aDoc->ChildDocumentCount();
+ for (uint32_t i = 0; i < childDocCount; i++) {
+ child = GetAccessibleInSubtree(aDoc->GetChildDocumentAt(i), aID);
+ if (child)
+ return child;
+ }
+
+ return nullptr;
+ }
+
+static already_AddRefed<IDispatch>
+GetProxiedAccessibleInSubtree(const DocAccessibleParent* aDoc,
+ const VARIANT& aVarChild)
+{
+ auto wrapper = static_cast<DocProxyAccessibleWrap*>(WrapperFor(aDoc));
+ RefPtr<IAccessible> comProxy;
+ int32_t wrapperChildId = AccessibleWrap::GetChildIDFor(wrapper);
+ if (wrapperChildId == aVarChild.lVal) {
+ wrapper->GetNativeInterface(getter_AddRefs(comProxy));
+ return comProxy.forget();
+ }
+
+ MOZ_ASSERT(aDoc->IsTopLevel());
+ if (!aDoc->IsTopLevel()) {
+ return nullptr;
+ }
+
+ wrapper->GetNativeInterface(getter_AddRefs(comProxy));
+ MOZ_ASSERT(comProxy);
+ if (!comProxy) {
+ return nullptr;
+ }
+
+ RefPtr<IDispatch> disp;
+ if (FAILED(comProxy->get_accChild(aVarChild, getter_AddRefs(disp)))) {
+ return nullptr;
+ }
+
+ return disp.forget();
+}
+
+already_AddRefed<IAccessible>
+AccessibleWrap::GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct)
+{
+ if (aVarChild.vt != VT_I4)
+ return nullptr;
+
+ VARIANT varChild = aVarChild;
+
+ MOZ_ASSERT(aIsDefunct);
+ *aIsDefunct = false;
+
+ RefPtr<IAccessible> result;
+
+ if (varChild.lVal == CHILDID_SELF) {
+ *aIsDefunct = IsDefunct();
+ if (*aIsDefunct) {
+ return nullptr;
+ }
+ GetNativeInterface(getter_AddRefs(result));
+ if (result) {
+ return result.forget();
+ }
+ // If we're not a proxy, there's nothing more we can do to attempt to
+ // resolve the IAccessible, so we just fail.
+ if (!IsProxy()) {
+ return nullptr;
+ }
+ // Otherwise, since we're a proxy and we have a null native interface, this
+ // indicates that we need to obtain a COM proxy. To do this, we'll replace
+ // CHILDID_SELF with our real MSAA ID and continue the search from there.
+ varChild.lVal = GetExistingID();
+ }
+
+ if (IsProxy() ? Proxy()->MustPruneChildren() : nsAccUtils::MustPrune(this)) {
+ return nullptr;
+ }
+
+ // If the MSAA ID is not a chrome id then we already know that we won't
+ // find it here and should look remotely instead.
+ if (XRE_IsParentProcess() && !sIDGen.IsChromeID(varChild.lVal)) {
+ return GetRemoteIAccessibleFor(varChild);
+ }
+ MOZ_ASSERT(XRE_IsParentProcess() ||
+ sIDGen.IsIDForThisContentProcess(varChild.lVal));
+
+ if (varChild.lVal > 0) {
+ // Gecko child indices are 0-based in contrast to indices used in MSAA.
+ MOZ_ASSERT(!IsProxy());
+ Accessible* xpAcc = GetChildAt(varChild.lVal - 1);
+ if (!xpAcc) {
+ return nullptr;
+ }
+ *aIsDefunct = xpAcc->IsDefunct();
+ static_cast<AccessibleWrap*>(xpAcc)->GetNativeInterface(getter_AddRefs(result));
+ return result.forget();
+ }
+
+ // If lVal negative then it is treated as child ID and we should look for
+ // accessible through whole accessible subtree including subdocuments.
+ // Otherwise we treat lVal as index in parent.
+ // First handle the case that both this accessible and the id'd one are in
+ // this process.
+ if (!IsProxy()) {
+ DocAccessible* document = Document();
+ Accessible* child =
+ GetAccessibleInSubtree(document, static_cast<uint32_t>(varChild.lVal));
+
+ // If it is a document then just return an accessible.
+ if (child && IsDoc()) {
+ *aIsDefunct = child->IsDefunct();
+ static_cast<AccessibleWrap*>(child)->GetNativeInterface(getter_AddRefs(result));
+ return result.forget();
+ }
+
+ // Otherwise check whether the accessible is a child (this path works for
+ // ARIA documents and popups).
+ Accessible* parent = child;
+ while (parent && parent != document) {
+ if (parent == this) {
+ *aIsDefunct = child->IsDefunct();
+ static_cast<AccessibleWrap*>(child)->GetNativeInterface(getter_AddRefs(result));
+ return result.forget();
+ }
+
+ parent = parent->Parent();
+ }
+ }
+
+ // Now see about the case that both this accessible and the target one are
+ // proxied.
+ if (IsProxy()) {
+ DocAccessibleParent* proxyDoc = Proxy()->Document();
+ RefPtr<IDispatch> disp = GetProxiedAccessibleInSubtree(proxyDoc, varChild);
+ if (!disp) {
+ return nullptr;
+ }
+
+ MOZ_ASSERT(mscom::IsProxy(disp));
+ DebugOnly<HRESULT> hr = disp->QueryInterface(IID_IAccessible,
+ getter_AddRefs(result));
+ MOZ_ASSERT(SUCCEEDED(hr));
+ return result.forget();
+ }
+
+ return nullptr;
+}
+
+already_AddRefed<IAccessible>
+AccessibleWrap::GetRemoteIAccessibleFor(const VARIANT& aVarChild)
+{
+ DocAccessibleParent* proxyDoc = nullptr;
+ DocAccessible* doc = Document();
+ const nsTArray<DocAccessibleParent*>* remoteDocs =
+ DocManager::TopLevelRemoteDocs();
+ if (!remoteDocs) {
+ return nullptr;
+ }
+
+ RefPtr<IAccessible> result;
+
+ size_t docCount = remoteDocs->Length();
+ for (size_t i = 0; i < docCount; i++) {
+ DocAccessibleParent* remoteDoc = remoteDocs->ElementAt(i);
+
+ uint32_t remoteDocMsaaId = WrapperFor(remoteDoc)->GetExistingID();
+ if (!sIDGen.IsSameContentProcessFor(aVarChild.lVal, remoteDocMsaaId)) {
+ continue;
+ }
+
+ Accessible* outerDoc = remoteDoc->OuterDocOfRemoteBrowser();
+ if (!outerDoc) {
+ continue;
+ }
+
+ if (outerDoc->Document() != doc) {
+ continue;
+ }
+
+ RefPtr<IDispatch> disp =
+ GetProxiedAccessibleInSubtree(remoteDoc, aVarChild);
+ if (!disp) {
+ continue;
+ }
+
+ DebugOnly<HRESULT> hr = disp->QueryInterface(IID_IAccessible,
+ getter_AddRefs(result));
+ MOZ_ASSERT(SUCCEEDED(hr));
+ return result.forget();
+ }
+
+ return nullptr;
+}
+
+void
+AccessibleWrap::UpdateSystemCaretFor(Accessible* aAccessible)
+{
+ // Move the system caret so that Windows Tablet Edition and tradional ATs with
+ // off-screen model can follow the caret
+ ::DestroyCaret();
+
+ HyperTextAccessible* text = aAccessible->AsHyperText();
+ if (!text)
+ return;
+
+ nsIWidget* widget = nullptr;
+ LayoutDeviceIntRect caretRect = text->GetCaretRect(&widget);
+ HWND caretWnd;
+ if (caretRect.IsEmpty() || !(caretWnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW))) {
+ return;
+ }
+
+ // Create invisible bitmap for caret, otherwise its appearance interferes
+ // with Gecko caret
+ HBITMAP caretBitMap = CreateBitmap(1, caretRect.height, 1, 1, nullptr);
+ if (::CreateCaret(caretWnd, caretBitMap, 1, caretRect.height)) { // Also destroys the last caret
+ ::ShowCaret(caretWnd);
+ RECT windowRect;
+ ::GetWindowRect(caretWnd, &windowRect);
+ ::SetCaretPos(caretRect.x - windowRect.left, caretRect.y - windowRect.top);
+ ::DeleteObject(caretBitMap);
+ }
+}
+
+ITypeInfo*
+AccessibleWrap::GetTI(LCID lcid)
+{
+ if (gTypeInfo)
+ return gTypeInfo;
+
+ ITypeLib *typeLib = nullptr;
+ HRESULT hr = LoadRegTypeLib(LIBID_Accessibility, 1, 0, lcid, &typeLib);
+ if (FAILED(hr))
+ return nullptr;
+
+ hr = typeLib->GetTypeInfoOfGuid(IID_IAccessible, &gTypeInfo);
+ typeLib->Release();
+
+ if (FAILED(hr))
+ return nullptr;
+
+ return gTypeInfo;
+}
+
+/* static */
+uint32_t
+AccessibleWrap::GetContentProcessIdFor(dom::ContentParentId aIPCContentId)
+{
+ return sIDGen.GetContentProcessIDFor(aIPCContentId);
+}
+
+/* static */
+void
+AccessibleWrap::ReleaseContentProcessIdFor(dom::ContentParentId aIPCContentId)
+{
+ sIDGen.ReleaseContentProcessIDFor(aIPCContentId);
+}
diff --git a/accessible/windows/msaa/AccessibleWrap.h b/accessible/windows/msaa/AccessibleWrap.h
new file mode 100644
index 000000000..eb97c2667
--- /dev/null
+++ b/accessible/windows/msaa/AccessibleWrap.h
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_AccessibleWrap_h_
+#define mozilla_a11y_AccessibleWrap_h_
+
+#include "nsCOMPtr.h"
+#include "Accessible.h"
+#include "Accessible2.h"
+#include "ia2Accessible.h"
+#include "ia2AccessibleComponent.h"
+#include "ia2AccessibleHyperlink.h"
+#include "ia2AccessibleValue.h"
+#include "mozilla/a11y/MsaaIdGenerator.h"
+#include "mozilla/a11y/ProxyAccessible.h"
+#include "mozilla/Attributes.h"
+
+#ifdef __GNUC__
+// Inheriting from both XPCOM and MSCOM interfaces causes a lot of warnings
+// about virtual functions being hidden by each other. This is done by
+// design, so silence the warning.
+#pragma GCC diagnostic ignored "-Woverloaded-virtual"
+#endif
+
+namespace mozilla {
+namespace a11y {
+class DocProxyAccessibleWrap;
+
+class AccessibleWrap : public Accessible,
+ public ia2Accessible,
+ public ia2AccessibleComponent,
+ public ia2AccessibleHyperlink,
+ public ia2AccessibleValue
+{
+public: // construction, destruction
+ AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc);
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ public: // IUnknown methods - see iunknown.h for documentation
+ STDMETHODIMP QueryInterface(REFIID, void**) override;
+
+ // Return the registered OLE class ID of this object's CfDataObj.
+ CLSID GetClassID() const;
+
+ public: // COM interface IAccessible
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accParent(
+ /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChildCount(
+ /* [retval][out] */ long __RPC_FAR *pcountChildren) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChild(
+ /* [in] */ VARIANT varChild,
+ /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accName(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszName) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszValue) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accDescription(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszDescription) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accRole(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarRole) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accState(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarState) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accHelp(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszHelp) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accHelpTopic(
+ /* [out] */ BSTR __RPC_FAR *pszHelpFile,
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ long __RPC_FAR *pidTopic) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszKeyboardShortcut) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accFocus(
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarChild) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accSelection(
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarChildren) override;
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accDefaultAction(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszDefaultAction) override;
+
+ virtual /* [id] */ HRESULT STDMETHODCALLTYPE accSelect(
+ /* [in] */ long flagsSelect,
+ /* [optional][in] */ VARIANT varChild) override;
+
+ virtual /* [id] */ HRESULT STDMETHODCALLTYPE accLocation(
+ /* [out] */ long __RPC_FAR *pxLeft,
+ /* [out] */ long __RPC_FAR *pyTop,
+ /* [out] */ long __RPC_FAR *pcxWidth,
+ /* [out] */ long __RPC_FAR *pcyHeight,
+ /* [optional][in] */ VARIANT varChild) override;
+
+ virtual /* [id] */ HRESULT STDMETHODCALLTYPE accNavigate(
+ /* [in] */ long navDir,
+ /* [optional][in] */ VARIANT varStart,
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt) override;
+
+ virtual /* [id] */ HRESULT STDMETHODCALLTYPE accHitTest(
+ /* [in] */ long xLeft,
+ /* [in] */ long yTop,
+ /* [retval][out] */ VARIANT __RPC_FAR *pvarChild) override;
+
+ virtual /* [id] */ HRESULT STDMETHODCALLTYPE accDoDefaultAction(
+ /* [optional][in] */ VARIANT varChild) override;
+
+ virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_accName(
+ /* [optional][in] */ VARIANT varChild,
+ /* [in] */ BSTR szName) override;
+
+ virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_accValue(
+ /* [optional][in] */ VARIANT varChild,
+ /* [in] */ BSTR szValue) override;
+
+ // IDispatch (support of scripting languages like VB)
+ virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo) override;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
+ ITypeInfo **ppTInfo) override;
+
+ virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
+ LPOLESTR *rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID *rgDispId) override;
+
+ virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
+ LCID lcid, WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *puArgErr) override;
+
+ // Accessible
+ virtual nsresult HandleAccEvent(AccEvent* aEvent) override;
+ virtual void Shutdown() override;
+
+ // Helper methods
+ static int32_t GetChildIDFor(Accessible* aAccessible);
+ static HWND GetHWNDFor(Accessible* aAccessible);
+
+ static void FireWinEvent(Accessible* aTarget, uint32_t aEventType);
+
+ /**
+ * System caret support: update the Windows caret position.
+ * The system caret works more universally than the MSAA caret
+ * For example, Window-Eyes, JAWS, ZoomText and Windows Tablet Edition use it
+ * We will use an invisible system caret.
+ * Gecko is still responsible for drawing its own caret
+ */
+ void UpdateSystemCaretFor(Accessible* aAccessible);
+
+ /**
+ * Find an accessible by the given child ID in cached documents.
+ */
+ MOZ_MUST_USE already_AddRefed<IAccessible>
+ GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct);
+
+ virtual void GetNativeInterface(void **aOutAccessible) override;
+
+ static IDispatch* NativeAccessible(Accessible* aAccessible);
+
+ uint32_t GetExistingID() const { return mID; }
+ static const uint32_t kNoID = 0;
+ void SetID(uint32_t aID);
+
+ static uint32_t GetContentProcessIdFor(dom::ContentParentId aIPCContentId);
+ static void ReleaseContentProcessIdFor(dom::ContentParentId aIPCContentId);
+
+protected:
+ virtual ~AccessibleWrap();
+
+ uint32_t mID;
+
+ HRESULT
+ ResolveChild(const VARIANT& aVarChild, IAccessible** aOutInterface);
+
+ /**
+ * Find a remote accessible by the given child ID.
+ */
+ MOZ_MUST_USE already_AddRefed<IAccessible>
+ GetRemoteIAccessibleFor(const VARIANT& aVarChild);
+
+ /**
+ * Return the wrapper for the document's proxy.
+ */
+ DocProxyAccessibleWrap* DocProxyWrapper() const;
+
+ /**
+ * Creates ITypeInfo for LIBID_Accessibility if it's needed and returns it.
+ */
+ static ITypeInfo* GetTI(LCID lcid);
+
+ static ITypeInfo* gTypeInfo;
+
+ static MsaaIdGenerator sIDGen;
+
+ enum navRelations {
+ NAVRELATION_CONTROLLED_BY = 0x1000,
+ NAVRELATION_CONTROLLER_FOR = 0x1001,
+ NAVRELATION_LABEL_FOR = 0x1002,
+ NAVRELATION_LABELLED_BY = 0x1003,
+ NAVRELATION_MEMBER_OF = 0x1004,
+ NAVRELATION_NODE_CHILD_OF = 0x1005,
+ NAVRELATION_FLOWS_TO = 0x1006,
+ NAVRELATION_FLOWS_FROM = 0x1007,
+ NAVRELATION_SUBWINDOW_OF = 0x1008,
+ NAVRELATION_EMBEDS = 0x1009,
+ NAVRELATION_EMBEDDED_BY = 0x100a,
+ NAVRELATION_POPUP_FOR = 0x100b,
+ NAVRELATION_PARENT_WINDOW_OF = 0x100c,
+ NAVRELATION_DEFAULT_BUTTON = 0x100d,
+ NAVRELATION_DESCRIBED_BY = 0x100e,
+ NAVRELATION_DESCRIPTION_FOR = 0x100f,
+ NAVRELATION_NODE_PARENT_OF = 0x1010,
+ NAVRELATION_CONTAINING_DOCUMENT = 0x1011,
+ NAVRELATION_CONTAINING_TAB_PANE = 0x1012,
+ NAVRELATION_CONTAINING_APPLICATION = 0x1014,
+ NAVRELATION_DETAILS = 0x1015,
+ NAVRELATION_DETAILS_FOR = 0x1016,
+ NAVRELATION_ERROR = 0x1017,
+ NAVRELATION_ERROR_FOR = 0x1018
+ };
+};
+
+static inline AccessibleWrap*
+WrapperFor(const ProxyAccessible* aProxy)
+{
+ return reinterpret_cast<AccessibleWrap*>(aProxy->GetWrapper());
+}
+
+} // namespace a11y
+} // namespace mozilla
+
+#ifdef XP_WIN
+// Undo the windows.h damage
+#undef GetMessage
+#undef CreateEvent
+#undef GetClassName
+#undef GetBinaryType
+#undef RemoveDirectory
+#endif
+
+#endif
diff --git a/accessible/windows/msaa/ApplicationAccessibleWrap.cpp b/accessible/windows/msaa/ApplicationAccessibleWrap.cpp
new file mode 100644
index 000000000..b78a8dd55
--- /dev/null
+++ b/accessible/windows/msaa/ApplicationAccessibleWrap.cpp
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ApplicationAccessibleWrap.h"
+
+#include "AccessibleApplication_i.c"
+#include "IUnknownImpl.h"
+
+#include "nsIGfxInfo.h"
+#include "nsIPersistentProperties2.h"
+#include "nsServiceManagerUtils.h"
+#include "mozilla/Services.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// nsISupports
+NS_IMPL_ISUPPORTS_INHERITED0(ApplicationAccessibleWrap,
+ ApplicationAccessible)
+
+already_AddRefed<nsIPersistentProperties>
+ApplicationAccessibleWrap::NativeAttributes()
+{
+ nsCOMPtr<nsIPersistentProperties> attributes =
+ do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
+
+ nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+ if (gfxInfo) {
+ bool isD2DEnabled = false;
+ gfxInfo->GetD2DEnabled(&isD2DEnabled);
+ nsAutoString unused;
+ attributes->SetStringProperty(
+ NS_LITERAL_CSTRING("D2D"),
+ isD2DEnabled ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false"),
+ unused);
+ }
+
+ return attributes.forget();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IUnknown
+
+STDMETHODIMP
+ApplicationAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
+{
+ if (!ppv)
+ return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleApplication == iid) {
+ *ppv = static_cast<IAccessibleApplication*>(this);
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return AccessibleWrap::QueryInterface(iid, ppv);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessibleApplication
+
+STDMETHODIMP
+ApplicationAccessibleWrap::get_appName(BSTR* aName)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aName)
+ return E_INVALIDARG;
+
+ *aName = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString name;
+ AppName(name);
+ if (name.IsEmpty())
+ return S_FALSE;
+
+ *aName = ::SysAllocStringLen(name.get(), name.Length());
+ return *aName ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ApplicationAccessibleWrap::get_appVersion(BSTR* aVersion)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aVersion)
+ return E_INVALIDARG;
+
+ *aVersion = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString version;
+ AppVersion(version);
+ if (version.IsEmpty())
+ return S_FALSE;
+
+ *aVersion = ::SysAllocStringLen(version.get(), version.Length());
+ return *aVersion ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ApplicationAccessibleWrap::get_toolkitName(BSTR* aName)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aName)
+ return E_INVALIDARG;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString name;
+ PlatformName(name);
+ if (name.IsEmpty())
+ return S_FALSE;
+
+ *aName = ::SysAllocStringLen(name.get(), name.Length());
+ return *aName ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ApplicationAccessibleWrap::get_toolkitVersion(BSTR* aVersion)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aVersion)
+ return E_INVALIDARG;
+
+ *aVersion = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString version;
+ PlatformVersion(version);
+ if (version.IsEmpty())
+ return S_FALSE;
+
+ *aVersion = ::SysAllocStringLen(version.get(), version.Length());
+ return *aVersion ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
diff --git a/accessible/windows/msaa/ApplicationAccessibleWrap.h b/accessible/windows/msaa/ApplicationAccessibleWrap.h
new file mode 100644
index 000000000..a427e98f5
--- /dev/null
+++ b/accessible/windows/msaa/ApplicationAccessibleWrap.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_ApplicationAccessibleWrap_h__
+#define mozilla_a11y_ApplicationAccessibleWrap_h__
+
+#include "ApplicationAccessible.h"
+
+#include "AccessibleApplication.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ApplicationAccessibleWrap: public ApplicationAccessible,
+ public IAccessibleApplication
+{
+ ~ApplicationAccessibleWrap() {}
+
+public:
+ // nsISupporst
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // nsAccessible
+ virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID, void**);
+
+ // IAccessibleApplication
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_appName(
+ /* [retval][out] */ BSTR *name);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_appVersion(
+ /* [retval][out] */ BSTR *version);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_toolkitName(
+ /* [retval][out] */ BSTR *name);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_toolkitVersion(
+ /* [retval][out] */ BSTR *version);
+
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
+
diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp
new file mode 100644
index 000000000..31026c586
--- /dev/null
+++ b/accessible/windows/msaa/Compatibility.cpp
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Compatibility.h"
+
+#include "nsWinUtils.h"
+#include "Statistics.h"
+
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+/**
+ * Return true if module version is lesser than the given version.
+ */
+bool
+IsModuleVersionLessThan(HMODULE aModuleHandle, DWORD aMajor, DWORD aMinor)
+{
+ wchar_t fileName[MAX_PATH];
+ ::GetModuleFileNameW(aModuleHandle, fileName, MAX_PATH);
+
+ DWORD dummy = 0;
+ DWORD length = ::GetFileVersionInfoSizeW(fileName, &dummy);
+
+ LPBYTE versionInfo = new BYTE[length];
+ ::GetFileVersionInfoW(fileName, 0, length, versionInfo);
+
+ UINT uLen;
+ VS_FIXEDFILEINFO* fixedFileInfo = nullptr;
+ ::VerQueryValueW(versionInfo, L"\\", (LPVOID*)&fixedFileInfo, &uLen);
+ DWORD dwFileVersionMS = fixedFileInfo->dwFileVersionMS;
+ DWORD dwFileVersionLS = fixedFileInfo->dwFileVersionLS;
+ delete [] versionInfo;
+
+ DWORD dwLeftMost = HIWORD(dwFileVersionMS);
+ DWORD dwSecondRight = HIWORD(dwFileVersionLS);
+ return (dwLeftMost < aMajor ||
+ (dwLeftMost == aMajor && dwSecondRight < aMinor));
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Compatibility
+////////////////////////////////////////////////////////////////////////////////
+
+uint32_t Compatibility::sConsumers = Compatibility::UNKNOWN;
+
+void
+Compatibility::Init()
+{
+ // Note we collect some AT statistics/telemetry here for convenience.
+
+ HMODULE jawsHandle = ::GetModuleHandleW(L"jhook");
+ if (jawsHandle)
+ sConsumers |= (IsModuleVersionLessThan(jawsHandle, 8, 2173)) ?
+ OLDJAWS : JAWS;
+
+ if (::GetModuleHandleW(L"gwm32inc"))
+ sConsumers |= WE;
+
+ if (::GetModuleHandleW(L"dolwinhk"))
+ sConsumers |= DOLPHIN;
+
+ if (::GetModuleHandleW(L"STSA32"))
+ sConsumers |= SEROTEK;
+
+ if (::GetModuleHandleW(L"nvdaHelperRemote"))
+ sConsumers |= NVDA;
+
+ if (::GetModuleHandleW(L"OsmHooks"))
+ sConsumers |= COBRA;
+
+ if (::GetModuleHandleW(L"WebFinderRemote"))
+ sConsumers |= ZOOMTEXT;
+
+ if (::GetModuleHandleW(L"Kazahook"))
+ sConsumers |= KAZAGURU;
+
+ if (::GetModuleHandleW(L"TextExtractorImpl32") ||
+ ::GetModuleHandleW(L"TextExtractorImpl64"))
+ sConsumers |= YOUDAO;
+
+ if (::GetModuleHandleW(L"uiautomation") ||
+ ::GetModuleHandleW(L"uiautomationcore"))
+ sConsumers |= UIAUTOMATION;
+
+ // If we have a known consumer remove the unknown bit.
+ if (sConsumers != Compatibility::UNKNOWN)
+ sConsumers ^= Compatibility::UNKNOWN;
+
+ // Gather telemetry
+ uint32_t temp = sConsumers;
+ for (int i = 0; temp; i++) {
+ if (temp & 0x1)
+ statistics::A11yConsumers(i);
+
+ temp >>= 1;
+ }
+
+ // Turn off new tab switching for Jaws and WE.
+ if (sConsumers & (JAWS | OLDJAWS | WE)) {
+ // Check to see if the pref for disallowing CtrlTab is already set. If so,
+ // bail out (respect the user settings). If not, set it.
+ if (!Preferences::HasUserValue("browser.ctrlTab.disallowForScreenReaders"))
+ Preferences::SetBool("browser.ctrlTab.disallowForScreenReaders", true);
+ }
+}
+
diff --git a/accessible/windows/msaa/Compatibility.h b/accessible/windows/msaa/Compatibility.h
new file mode 100644
index 000000000..dd9a82f7c
--- /dev/null
+++ b/accessible/windows/msaa/Compatibility.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef COMPATIBILITY_MANAGER_H
+#define COMPATIBILITY_MANAGER_H
+
+#include <stdint.h>
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * Used to get compatibility modes. Note, modes are computed at accessibility
+ * start up time and aren't changed during lifetime.
+ */
+class Compatibility
+{
+public:
+ /**
+ * Return true if IAccessible2 disabled.
+ */
+ static bool IsIA2Off() { return !!(sConsumers & OLDJAWS); }
+
+ /**
+ * Return true if JAWS mode is enabled.
+ */
+ static bool IsJAWS() { return !!(sConsumers & (JAWS | OLDJAWS)); }
+
+ /**
+ * Return true if WE mode is enabled.
+ */
+ static bool IsWE() { return !!(sConsumers & WE); }
+
+ /**
+ * Return true if Dolphin mode is enabled.
+ */
+ static bool IsDolphin() { return !!(sConsumers & DOLPHIN); }
+
+private:
+ Compatibility();
+ Compatibility(const Compatibility&);
+ Compatibility& operator = (const Compatibility&);
+
+ /**
+ * Initialize compatibility mode. Called by platform (see Platform.h) during
+ * accessibility initialization.
+ */
+ static void Init();
+ friend void PlatformInit();
+
+ /**
+ * List of detected consumers of a11y (used for statistics/telemetry and compat)
+ */
+ enum {
+ NVDA = 1 << 0,
+ JAWS = 1 << 1,
+ OLDJAWS = 1 << 2,
+ WE = 1 << 3,
+ DOLPHIN = 1 << 4,
+ SEROTEK = 1 << 5,
+ COBRA = 1 << 6,
+ ZOOMTEXT = 1 << 7,
+ KAZAGURU = 1 << 8,
+ YOUDAO = 1 << 9,
+ UNKNOWN = 1 << 10,
+ UIAUTOMATION = 1 << 11
+ };
+
+private:
+ static uint32_t sConsumers;
+};
+
+} // a11y namespace
+} // mozilla namespace
+
+#endif
diff --git a/accessible/windows/msaa/DocAccessibleWrap.cpp b/accessible/windows/msaa/DocAccessibleWrap.cpp
new file mode 100644
index 000000000..6fb89816d
--- /dev/null
+++ b/accessible/windows/msaa/DocAccessibleWrap.cpp
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DocAccessibleWrap.h"
+
+#include "Compatibility.h"
+#include "DocAccessibleChild.h"
+#include "nsWinUtils.h"
+#include "Role.h"
+#include "RootAccessible.h"
+#include "sdnDocAccessible.h"
+#include "Statistics.h"
+
+#include "nsIDocShell.h"
+#include "nsIInterfaceRequestorUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// DocAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+DocAccessibleWrap::
+ DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+ DocAccessible(aDocument, aPresShell), mHWND(nullptr)
+{
+}
+
+DocAccessibleWrap::~DocAccessibleWrap()
+{
+}
+
+IMPL_IUNKNOWN_QUERY_HEAD(DocAccessibleWrap)
+ if (aIID == IID_ISimpleDOMDocument) {
+ statistics::ISimpleDOMUsed();
+ *aInstancePtr = static_cast<ISimpleDOMDocument*>(new sdnDocAccessible(this));
+ static_cast<IUnknown*>(*aInstancePtr)->AddRef();
+ return S_OK;
+ }
+IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(HyperTextAccessibleWrap)
+
+STDMETHODIMP
+DocAccessibleWrap::get_accParent(
+ /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
+{
+ // We might be a top-level document in a content process.
+ DocAccessibleChild* ipcDoc = IPCDoc();
+ if (!ipcDoc) {
+ return DocAccessible::get_accParent(ppdispParent);
+ }
+ IAccessible* dispParent = ipcDoc->GetParentIAccessible();
+ if (!dispParent) {
+ return S_FALSE;
+ }
+
+ dispParent->AddRef();
+ *ppdispParent = static_cast<IDispatch*>(dispParent);
+ return S_OK;
+}
+
+STDMETHODIMP
+DocAccessibleWrap::get_accValue(VARIANT aVarChild, BSTR __RPC_FAR* aValue)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aValue)
+ return E_INVALIDARG;
+ *aValue = nullptr;
+
+ // For backwards-compat, we still support old MSAA hack to provide URL in accValue
+ // Check for real value first
+ HRESULT hr = AccessibleWrap::get_accValue(aVarChild, aValue);
+ if (FAILED(hr) || *aValue || aVarChild.lVal != CHILDID_SELF)
+ return hr;
+
+ // If document is being used to create a widget, don't use the URL hack
+ roles::Role role = Role();
+ if (role != roles::DOCUMENT && role != roles::APPLICATION &&
+ role != roles::DIALOG && role != roles::ALERT)
+ return hr;
+
+ nsAutoString url;
+ URL(url);
+ if (url.IsEmpty())
+ return S_FALSE;
+
+ *aValue = ::SysAllocStringLen(url.get(), url.Length());
+ return *aValue ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Accessible
+
+void
+DocAccessibleWrap::Shutdown()
+{
+ // Do window emulation specific shutdown if emulation was started.
+ if (nsWinUtils::IsWindowEmulationStarted()) {
+ // Destroy window created for root document.
+ if (mDocFlags & eTabDocument) {
+ HWND hWnd = static_cast<HWND>(mHWND);
+ ::RemovePropW(hWnd, kPropNameDocAcc);
+ ::DestroyWindow(hWnd);
+ }
+
+ mHWND = nullptr;
+ }
+
+ DocAccessible::Shutdown();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DocAccessible public
+
+void*
+DocAccessibleWrap::GetNativeWindow() const
+{
+ return mHWND ? mHWND : DocAccessible::GetNativeWindow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DocAccessible protected
+
+void
+DocAccessibleWrap::DoInitialUpdate()
+{
+ DocAccessible::DoInitialUpdate();
+
+ if (nsWinUtils::IsWindowEmulationStarted()) {
+ // Create window for tab document.
+ if (mDocFlags & eTabDocument) {
+ a11y::RootAccessible* rootDocument = RootAccessible();
+ bool isActive = true;
+ nsIntRect rect(CW_USEDEFAULT, CW_USEDEFAULT, 0, 0);
+ if (Compatibility::IsDolphin()) {
+ rect = Bounds();
+ nsIntRect rootRect = rootDocument->Bounds();
+ rect.x = rootRect.x - rect.x;
+ rect.y -= rootRect.y;
+
+ nsCOMPtr<nsISupports> container = mDocumentNode->GetContainer();
+ nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
+ docShell->GetIsActive(&isActive);
+ }
+
+ HWND parentWnd = reinterpret_cast<HWND>(rootDocument->GetNativeWindow());
+ mHWND = nsWinUtils::CreateNativeWindow(kClassNameTabContent, parentWnd,
+ rect.x, rect.y,
+ rect.width, rect.height, isActive);
+
+ ::SetPropW(static_cast<HWND>(mHWND), kPropNameDocAcc, (HANDLE)this);
+
+ } else {
+ DocAccessible* parentDocument = ParentDocument();
+ if (parentDocument)
+ mHWND = parentDocument->GetNativeWindow();
+ }
+ }
+}
diff --git a/accessible/windows/msaa/DocAccessibleWrap.h b/accessible/windows/msaa/DocAccessibleWrap.h
new file mode 100644
index 000000000..effa23848
--- /dev/null
+++ b/accessible/windows/msaa/DocAccessibleWrap.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_DocAccessibleWrap_h__
+#define mozilla_a11y_DocAccessibleWrap_h__
+
+#include "DocAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+class DocAccessibleWrap : public DocAccessible
+{
+public:
+ DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+ virtual ~DocAccessibleWrap();
+
+ DECL_IUNKNOWN_INHERITED
+
+ // IAccessible
+
+ // Override get_accParent for e10s
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accParent(
+ /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent) override;
+
+ // Override get_accValue to provide URL when no other value is available
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue(
+ /* [optional][in] */ VARIANT varChild,
+ /* [retval][out] */ BSTR __RPC_FAR *pszValue) override;
+
+ // Accessible
+ virtual void Shutdown();
+
+ // DocAccessible
+ virtual void* GetNativeWindow() const;
+
+ /**
+ * Manage the mapping from id to Accessible.
+ */
+ void AddID(uint32_t aID, AccessibleWrap* aAcc)
+ { mIDToAccessibleMap.Put(aID, aAcc); }
+ void RemoveID(uint32_t aID) { mIDToAccessibleMap.Remove(aID); }
+ AccessibleWrap* GetAccessibleByID(uint32_t aID) const
+ { return mIDToAccessibleMap.Get(aID); }
+
+protected:
+ // DocAccessible
+ virtual void DoInitialUpdate();
+
+protected:
+ void* mHWND;
+
+ /*
+ * This provides a mapping from 32 bit id to accessible objects.
+ */
+ nsDataHashtable<nsUint32HashKey, AccessibleWrap*> mIDToAccessibleMap;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/msaa/EnumVariant.cpp b/accessible/windows/msaa/EnumVariant.cpp
new file mode 100644
index 000000000..86c81a105
--- /dev/null
+++ b/accessible/windows/msaa/EnumVariant.cpp
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "EnumVariant.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// ChildrenEnumVariant
+////////////////////////////////////////////////////////////////////////////////
+
+IMPL_IUNKNOWN_QUERY_HEAD(ChildrenEnumVariant)
+IMPL_IUNKNOWN_QUERY_IFACE(IEnumVARIANT)
+IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mAnchorAcc)
+
+STDMETHODIMP
+ChildrenEnumVariant::Next(ULONG aCount, VARIANT FAR* aItems,
+ ULONG FAR* aCountFetched)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aItems || !aCountFetched)
+ return E_INVALIDARG;
+
+ *aCountFetched = 0;
+
+ if (mAnchorAcc->IsDefunct() || mAnchorAcc->GetChildAt(mCurIndex) != mCurAcc)
+ return CO_E_OBJNOTCONNECTED;
+
+ ULONG countFetched = 0;
+ while (mCurAcc && countFetched < aCount) {
+ VariantInit(aItems + countFetched);
+
+ IDispatch* accNative = AccessibleWrap::NativeAccessible(mCurAcc);
+
+ ++mCurIndex;
+ mCurAcc = mAnchorAcc->GetChildAt(mCurIndex);
+
+ // Don't output the accessible and count it as having been fetched unless
+ // it is non-null
+ MOZ_ASSERT(accNative);
+ if (!accNative) {
+ continue;
+ }
+
+ aItems[countFetched].pdispVal = accNative;
+ aItems[countFetched].vt = VT_DISPATCH;
+ ++countFetched;
+ }
+
+ (*aCountFetched) = countFetched;
+
+ return countFetched < aCount ? S_FALSE : S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ChildrenEnumVariant::Skip(ULONG aCount)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (mAnchorAcc->IsDefunct() || mAnchorAcc->GetChildAt(mCurIndex) != mCurAcc)
+ return CO_E_OBJNOTCONNECTED;
+
+ mCurIndex += aCount;
+ mCurAcc = mAnchorAcc->GetChildAt(mCurIndex);
+
+ return mCurAcc ? S_OK : S_FALSE;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ChildrenEnumVariant::Reset()
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (mAnchorAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ mCurIndex = 0;
+ mCurAcc = mAnchorAcc->GetChildAt(0);
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+ChildrenEnumVariant::Clone(IEnumVARIANT** aEnumVariant)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aEnumVariant)
+ return E_INVALIDARG;
+
+ *aEnumVariant = new ChildrenEnumVariant(*this);
+ (*aEnumVariant)->AddRef();
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
diff --git a/accessible/windows/msaa/EnumVariant.h b/accessible/windows/msaa/EnumVariant.h
new file mode 100644
index 000000000..39e342dd5
--- /dev/null
+++ b/accessible/windows/msaa/EnumVariant.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_EnumVariant_h__
+#define mozilla_a11y_EnumVariant_h__
+
+#include "AccessibleWrap.h"
+#include "IUnknownImpl.h"
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * Used to fetch accessible children.
+ */
+class ChildrenEnumVariant final : public IEnumVARIANT
+{
+public:
+ ChildrenEnumVariant(AccessibleWrap* aAnchor) : mAnchorAcc(aAnchor),
+ mCurAcc(mAnchorAcc->GetChildAt(0)), mCurIndex(0) { }
+
+ // IUnknown
+ DECL_IUNKNOWN
+
+ // IEnumVariant
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG aCount,
+ /* [length_is][size_is][out] */ VARIANT* aItems,
+ /* [out] */ ULONG* aCountFetched);
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG aCount);
+
+ virtual HRESULT STDMETHODCALLTYPE Reset();
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ IEnumVARIANT** aEnumVaraint);
+
+private:
+ ChildrenEnumVariant() = delete;
+ ChildrenEnumVariant& operator =(const ChildrenEnumVariant&) = delete;
+
+ ChildrenEnumVariant(const ChildrenEnumVariant& aEnumVariant) :
+ mAnchorAcc(aEnumVariant.mAnchorAcc), mCurAcc(aEnumVariant.mCurAcc),
+ mCurIndex(aEnumVariant.mCurIndex) { }
+ virtual ~ChildrenEnumVariant() { }
+
+protected:
+ RefPtr<AccessibleWrap> mAnchorAcc;
+ Accessible* mCurAcc;
+ uint32_t mCurIndex;
+};
+
+} // a11y namespace
+} // mozilla namespace
+
+#endif
diff --git a/accessible/windows/msaa/HTMLTableAccessibleWrap.cpp b/accessible/windows/msaa/HTMLTableAccessibleWrap.cpp
new file mode 100644
index 000000000..13cea8853
--- /dev/null
+++ b/accessible/windows/msaa/HTMLTableAccessibleWrap.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "HTMLTableAccessibleWrap.h"
+
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLTableAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableAccessibleWrap,
+ HTMLTableAccessible)
+
+IMPL_IUNKNOWN_INHERITED1(HTMLTableAccessibleWrap,
+ AccessibleWrap,
+ ia2AccessibleTable)
+
+void
+HTMLTableAccessibleWrap::Shutdown()
+{
+ ia2AccessibleTable::mTable = nullptr;
+ HTMLTableAccessible::Shutdown();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLTableCellAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableCellAccessibleWrap,
+ HTMLTableCellAccessible)
+
+IMPL_IUNKNOWN_INHERITED1(HTMLTableCellAccessibleWrap,
+ HyperTextAccessibleWrap,
+ ia2AccessibleTableCell)
+
+void
+HTMLTableCellAccessibleWrap::Shutdown()
+{
+ ia2AccessibleTableCell::mTableCell = nullptr;
+ HTMLTableCellAccessible::Shutdown();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLTableCellAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableHeaderCellAccessibleWrap,
+ HTMLTableHeaderCellAccessible)
+
+IMPL_IUNKNOWN_INHERITED1(HTMLTableHeaderCellAccessibleWrap,
+ HyperTextAccessibleWrap,
+ ia2AccessibleTableCell)
+
+void
+HTMLTableHeaderCellAccessibleWrap::Shutdown()
+{
+ ia2AccessibleTableCell::mTableCell = nullptr;
+ HTMLTableHeaderCellAccessible::Shutdown();
+}
diff --git a/accessible/windows/msaa/HTMLTableAccessibleWrap.h b/accessible/windows/msaa/HTMLTableAccessibleWrap.h
new file mode 100644
index 000000000..71d149a3c
--- /dev/null
+++ b/accessible/windows/msaa/HTMLTableAccessibleWrap.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_HTMLTableAccessibleWrap_h__
+#define mozilla_a11y_HTMLTableAccessibleWrap_h__
+
+#include "HTMLTableAccessible.h"
+
+#include "ia2AccessibleTable.h"
+#include "ia2AccessibleTableCell.h"
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * IA2 wrapper class for HTMLTableAccessible implementing IAccessibleTable
+ * and IAccessibleTable2 interfaces.
+ */
+class HTMLTableAccessibleWrap : public HTMLTableAccessible,
+ public ia2AccessibleTable
+{
+ ~HTMLTableAccessibleWrap() {}
+
+public:
+ HTMLTableAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ HTMLTableAccessible(aContent, aDoc), ia2AccessibleTable(this) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ virtual void Shutdown() override;
+};
+
+
+/**
+ * IA2 wrapper class for HTMLTableCellAccessible implementing
+ * IAccessibleTableCell interface.
+ */
+class HTMLTableCellAccessibleWrap : public HTMLTableCellAccessible,
+ public ia2AccessibleTableCell
+{
+ ~HTMLTableCellAccessibleWrap() {}
+
+public:
+ HTMLTableCellAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ HTMLTableCellAccessible(aContent, aDoc), ia2AccessibleTableCell(this) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ virtual void Shutdown() override;
+};
+
+
+/**
+ * IA2 wrapper class for HTMLTableHeaderCellAccessible implementing
+ * IAccessibleTableCell interface.
+ */
+class HTMLTableHeaderCellAccessibleWrap : public HTMLTableHeaderCellAccessible,
+ public ia2AccessibleTableCell
+{
+ ~HTMLTableHeaderCellAccessibleWrap() {}
+
+public:
+ HTMLTableHeaderCellAccessibleWrap(nsIContent* aContent,
+ DocAccessible* aDoc) :
+ HTMLTableHeaderCellAccessible(aContent, aDoc), ia2AccessibleTableCell(this)
+ {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ virtual void Shutdown() override;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
+
diff --git a/accessible/windows/msaa/HTMLWin32ObjectAccessible.cpp b/accessible/windows/msaa/HTMLWin32ObjectAccessible.cpp
new file mode 100644
index 000000000..3644db68d
--- /dev/null
+++ b/accessible/windows/msaa/HTMLWin32ObjectAccessible.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "HTMLWin32ObjectAccessible.h"
+
+#include "Role.h"
+#include "States.h"
+
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLWin32ObjectOwnerAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+HTMLWin32ObjectOwnerAccessible::
+ HTMLWin32ObjectOwnerAccessible(nsIContent* aContent,
+ DocAccessible* aDoc, void* aHwnd) :
+ AccessibleWrap(aContent, aDoc), mHwnd(aHwnd)
+{
+ mStateFlags |= eNoKidsFromDOM;
+
+ // Our only child is a HTMLWin32ObjectAccessible object.
+ if (mHwnd) {
+ mNativeAccessible = new HTMLWin32ObjectAccessible(mHwnd, aDoc);
+ AppendChild(mNativeAccessible);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLWin32ObjectOwnerAccessible: Accessible implementation
+
+void
+HTMLWin32ObjectOwnerAccessible::Shutdown()
+{
+ AccessibleWrap::Shutdown();
+ mNativeAccessible = nullptr;
+}
+
+role
+HTMLWin32ObjectOwnerAccessible::NativeRole()
+{
+ return roles::EMBEDDED_OBJECT;
+}
+
+bool
+HTMLWin32ObjectOwnerAccessible::NativelyUnavailable() const
+{
+ // XXX: No HWND means this is windowless plugin which is not accessible in
+ // the meantime.
+ return !mHwnd;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLWin32ObjectAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+HTMLWin32ObjectAccessible::HTMLWin32ObjectAccessible(void* aHwnd,
+ DocAccessible* aDoc) :
+ DummyAccessible(aDoc)
+{
+ mHwnd = aHwnd;
+ if (mHwnd) {
+#if defined(MOZ_CONTENT_SANDBOX)
+ if (XRE_IsContentProcess()) {
+ DocAccessibleChild* ipcDoc = aDoc->IPCDoc();
+ MOZ_ASSERT(ipcDoc);
+ if (!ipcDoc) {
+ return;
+ }
+
+ IAccessibleHolder proxyHolder;
+ if (!ipcDoc->SendGetWindowedPluginIAccessible(
+ reinterpret_cast<uintptr_t>(mHwnd), &proxyHolder)) {
+ return;
+ }
+
+ mCOMProxy.reset(proxyHolder.Release());
+ return;
+ }
+#endif
+
+ // The plugin is not windowless. In this situation we use
+ // use its inner child owned by the plugin so that we don't get
+ // in an infinite loop, where the WM_GETOBJECT's get forwarded
+ // back to us and create another HTMLWin32ObjectAccessible
+ mHwnd = ::GetWindow((HWND)aHwnd, GW_CHILD);
+ }
+}
+
+void
+HTMLWin32ObjectAccessible::GetNativeInterface(void** aNativeAccessible)
+{
+#if defined(MOZ_CONTENT_SANDBOX)
+ if (XRE_IsContentProcess()) {
+ RefPtr<IAccessible> addRefed = mCOMProxy.get();
+ addRefed.forget(aNativeAccessible);
+ return;
+ }
+#endif
+
+ if (mHwnd) {
+ ::AccessibleObjectFromWindow(static_cast<HWND>(mHwnd),
+ OBJID_WINDOW, IID_IAccessible,
+ aNativeAccessible);
+ }
+}
+
diff --git a/accessible/windows/msaa/HTMLWin32ObjectAccessible.h b/accessible/windows/msaa/HTMLWin32ObjectAccessible.h
new file mode 100644
index 000000000..786d52191
--- /dev/null
+++ b/accessible/windows/msaa/HTMLWin32ObjectAccessible.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_HTMLWin32ObjectAccessible_h_
+#define mozilla_a11y_HTMLWin32ObjectAccessible_h_
+
+#include "BaseAccessibles.h"
+
+#if defined(MOZ_CONTENT_SANDBOX)
+#include "mozilla/mscom/Ptr.h"
+#endif
+
+struct IAccessible;
+
+namespace mozilla {
+namespace a11y {
+
+class HTMLWin32ObjectOwnerAccessible : public AccessibleWrap
+{
+public:
+ // This will own the HTMLWin32ObjectAccessible. We create this where the
+ // <object> or <embed> exists in the tree, so that get_accNextSibling() etc.
+ // will still point to Gecko accessible sibling content. This is necessary
+ // because the native plugin accessible doesn't know where it exists in the
+ // Mozilla tree, and returns null for previous and next sibling. This would
+ // have the effect of cutting off all content after the plugin.
+ HTMLWin32ObjectOwnerAccessible(nsIContent* aContent,
+ DocAccessible* aDoc, void* aHwnd);
+ virtual ~HTMLWin32ObjectOwnerAccessible() {}
+
+ // Accessible
+ virtual void Shutdown();
+ virtual mozilla::a11y::role NativeRole();
+ virtual bool NativelyUnavailable() const;
+
+protected:
+ void* mHwnd;
+ RefPtr<Accessible> mNativeAccessible;
+};
+
+/**
+ * This class is used only internally, we never! send out an IAccessible linked
+ * back to this object. This class is used to represent a plugin object when
+ * referenced as a child or sibling of another Accessible node. We need only
+ * a limited portion of the Accessible interface implemented here. The
+ * in depth accessible information will be returned by the actual IAccessible
+ * object returned by us in Accessible::NewAccessible() that gets the IAccessible
+ * from the windows system from the window handle.
+ */
+class HTMLWin32ObjectAccessible : public DummyAccessible
+{
+public:
+ HTMLWin32ObjectAccessible(void* aHwnd, DocAccessible* aDoc);
+ virtual ~HTMLWin32ObjectAccessible() {}
+
+ virtual void GetNativeInterface(void** aNativeAccessible) override;
+
+protected:
+ void* mHwnd;
+#if defined(MOZ_CONTENT_SANDBOX)
+ mscom::ProxyUniquePtr<IAccessible> mCOMProxy;
+#endif
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/msaa/HyperTextAccessibleWrap.cpp b/accessible/windows/msaa/HyperTextAccessibleWrap.cpp
new file mode 100644
index 000000000..b5fd716d9
--- /dev/null
+++ b/accessible/windows/msaa/HyperTextAccessibleWrap.cpp
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "HyperTextAccessibleWrap.h"
+#include "Accessible-inl.h"
+
+#include "nsEventShell.h"
+
+#include "mozilla/StaticPtr.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+NS_IMPL_ISUPPORTS_INHERITED0(HyperTextAccessibleWrap,
+ HyperTextAccessible)
+
+STDMETHODIMP
+HyperTextAccessibleWrap::QueryInterface(REFIID aIID, void** aInstancePtr)
+{
+ if (!aInstancePtr)
+ return E_FAIL;
+
+ *aInstancePtr = nullptr;
+
+ if (IsTextRole()) {
+ if (aIID == IID_IAccessibleText)
+ *aInstancePtr =
+ static_cast<IAccessibleText*>(static_cast<ia2AccessibleText*>(this));
+ else if (aIID == IID_IAccessibleHypertext)
+ *aInstancePtr = static_cast<IAccessibleHypertext*>(this);
+ else if (aIID == IID_IAccessibleEditableText)
+ *aInstancePtr = static_cast<IAccessibleEditableText*>(this);
+
+ if (*aInstancePtr) {
+ AddRef();
+ return S_OK;
+ }
+ }
+
+ return AccessibleWrap::QueryInterface(aIID, aInstancePtr);
+}
+
+nsresult
+HyperTextAccessibleWrap::HandleAccEvent(AccEvent* aEvent)
+{
+ uint32_t eventType = aEvent->GetEventType();
+
+ if (eventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
+ eventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED) {
+ Accessible* accessible = aEvent->GetAccessible();
+ if (accessible && accessible->IsHyperText()) {
+ AccTextChangeEvent* event = downcast_accEvent(aEvent);
+ HyperTextAccessibleWrap* text =
+ static_cast<HyperTextAccessibleWrap*>(accessible->AsHyperText());
+ ia2AccessibleText::UpdateTextChangeData(text, event->IsTextInserted(),
+ event->ModifiedText(),
+ event->GetStartOffset(),
+ event->GetLength());
+ }
+ }
+
+ return HyperTextAccessible::HandleAccEvent(aEvent);
+}
diff --git a/accessible/windows/msaa/HyperTextAccessibleWrap.h b/accessible/windows/msaa/HyperTextAccessibleWrap.h
new file mode 100644
index 000000000..c0f853da2
--- /dev/null
+++ b/accessible/windows/msaa/HyperTextAccessibleWrap.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_HyperTextAccessibleWrap_h__
+#define mozilla_a11y_HyperTextAccessibleWrap_h__
+
+#include "HyperTextAccessible.h"
+#include "ia2AccessibleEditableText.h"
+#include "ia2AccessibleHypertext.h"
+#include "IUnknownImpl.h"
+
+namespace mozilla {
+template<class T> class StaticAutoPtr;
+template<class T> class StaticRefPtr;
+
+namespace a11y {
+
+class HyperTextAccessibleWrap : public HyperTextAccessible,
+ public ia2AccessibleHypertext,
+ public ia2AccessibleEditableText
+{
+public:
+ HyperTextAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ HyperTextAccessible(aContent, aDoc) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // Accessible
+ virtual nsresult HandleAccEvent(AccEvent* aEvent);
+
+protected:
+ ~HyperTextAccessibleWrap() {}
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/msaa/IDSet.h b/accessible/windows/msaa/IDSet.h
new file mode 100644
index 000000000..3c3ed74c3
--- /dev/null
+++ b/accessible/windows/msaa/IDSet.h
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * A class to generate unique IDs in the range [ - 2^31, 0 )
+ */
+
+#ifndef MOZILLA_A11Y_IDSet_h_
+#define MOZILLA_A11Y_IDSet_h_
+
+#include "mozilla/Attributes.h"
+#include "mozilla/MathAlgorithms.h"
+#include "mozilla/SplayTree.h"
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * On windows an accessible's id must be a negative 32 bit integer. It is
+ * important to support recycling arbitrary IDs because accessibles can be
+ * created and destroyed at any time in the life of a page. IDSet provides 2
+ * operations: generate an ID in the range (0, mMaxId], and release an ID so
+ * it can be allocated again. Allocated ID are tracked by a sparse bitmap
+ * implemented with a splay tree. Nodes in the tree are keyed by the upper N
+ * bits of the ID, and the node contains a bitmap tracking the allocation of
+ * 2^(ceil(log2(mMaxId)) - N) IDs.
+ *
+ * Note that negation is handled by MsaaIdGenerator as it performs additional
+ * decoration on the ID generated by IDSet.
+ * @see mozilla::a11y::MsaaIdGenerator
+ */
+class IDSet
+{
+public:
+ constexpr explicit IDSet(const uint32_t aMaxIdBits)
+ : mBitSet()
+ , mIdx(0)
+ , mMaxId((1UL << aMaxIdBits) - 1UL)
+ , mMaxIdx(mMaxId / bitsPerElt)
+ {
+ }
+
+ /**
+ * Return a new unique id.
+ */
+ uint32_t GetID()
+ {
+ uint32_t idx = mIdx;
+ while (true) {
+ BitSetElt* elt = mBitSet.findOrInsert(BitSetElt(idx));
+ if (elt->mBitvec[0] != UINT64_MAX) {
+ uint32_t i = CountTrailingZeroes64(~elt->mBitvec[0]);
+
+ elt->mBitvec[0] |= (1ull << i);
+ mIdx = idx;
+ return (elt->mIdx * bitsPerElt + i);
+ }
+
+ if (elt->mBitvec[1] != UINT64_MAX) {
+ uint32_t i = CountTrailingZeroes64(~elt->mBitvec[1]);
+
+ elt->mBitvec[1] |= (1ull << i);
+ mIdx = idx;
+ return (elt->mIdx * bitsPerElt + bitsPerWord + i);
+ }
+
+ idx++;
+ if (idx > mMaxIdx) {
+ idx = 0;
+ }
+
+ if (idx == mIdx) {
+ MOZ_CRASH("used up all the available ids");
+ }
+ }
+ }
+
+ /**
+ * Free a no longer required id so it may be allocated again.
+ */
+ void ReleaseID(uint32_t aID)
+ {
+ MOZ_ASSERT(aID < mMaxId);
+
+ uint32_t idx = aID / bitsPerElt;
+ mIdx = idx;
+ BitSetElt* elt = mBitSet.find(BitSetElt(idx));
+ MOZ_ASSERT(elt);
+
+ uint32_t vecIdx = (aID % bitsPerElt) / bitsPerWord;
+ elt->mBitvec[vecIdx] &= ~(1ull << (aID % bitsPerWord));
+ if (elt->mBitvec[0] == 0 && elt->mBitvec[1] == 0) {
+ delete mBitSet.remove(*elt);
+ }
+ }
+
+private:
+ static const unsigned int wordsPerElt = 2;
+ static const unsigned int bitsPerWord = 64;
+ static const unsigned int bitsPerElt = wordsPerElt * bitsPerWord;
+
+ struct BitSetElt : mozilla::SplayTreeNode<BitSetElt>
+ {
+ explicit BitSetElt(uint32_t aIdx) :
+ mIdx(aIdx)
+ { mBitvec[0] = mBitvec[1] = 0; }
+
+ uint64_t mBitvec[wordsPerElt];
+ uint32_t mIdx;
+
+ static int compare(const BitSetElt& a, const BitSetElt& b)
+ {
+ if (a.mIdx == b.mIdx) {
+ return 0;
+ }
+
+ if (a.mIdx < b.mIdx) {
+ return -1;
+ }
+ return 1;
+ }
+ };
+
+ SplayTree<BitSetElt, BitSetElt> mBitSet;
+ uint32_t mIdx;
+ const uint32_t mMaxId;
+ const uint32_t mMaxIdx;
+};
+
+}
+}
+
+#endif
diff --git a/accessible/windows/msaa/IUnknownImpl.cpp b/accessible/windows/msaa/IUnknownImpl.cpp
new file mode 100644
index 000000000..4a9fa5383
--- /dev/null
+++ b/accessible/windows/msaa/IUnknownImpl.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. *
+ */
+
+#include "IUnknownImpl.h"
+
+#include "nsDebug.h"
+
+#ifdef MOZ_CRASHREPORTER
+#include "nsExceptionHandler.h"
+#endif
+
+namespace mozilla {
+namespace a11y {
+
+HRESULT
+GetHRESULT(nsresult aResult)
+{
+ switch (aResult) {
+ case NS_OK:
+ return S_OK;
+
+ case NS_ERROR_INVALID_ARG:
+ return E_INVALIDARG;
+
+ case NS_ERROR_OUT_OF_MEMORY:
+ return E_OUTOFMEMORY;
+
+ case NS_ERROR_NOT_IMPLEMENTED:
+ return E_NOTIMPL;
+
+ default:
+ return E_FAIL;
+ }
+}
+
+int
+FilterExceptions(unsigned int aCode, EXCEPTION_POINTERS* aExceptionInfo)
+{
+ if (aCode == EXCEPTION_ACCESS_VIOLATION) {
+#ifdef MOZ_CRASHREPORTER
+ // MSAA swallows crashes (because it is COM-based) but we still need to
+ // learn about those crashes so we can fix them. Make sure to pass them to
+ // the crash reporter.
+ CrashReporter::WriteMinidumpForException(aExceptionInfo);
+#endif
+ } else {
+ NS_NOTREACHED("We should only be catching crash exceptions");
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+} // namespace a11y
+} // namespace mozilla
diff --git a/accessible/windows/msaa/IUnknownImpl.h b/accessible/windows/msaa/IUnknownImpl.h
new file mode 100644
index 000000000..dbf6c1374
--- /dev/null
+++ b/accessible/windows/msaa/IUnknownImpl.h
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. *
+ */
+
+#ifndef mozilla_a11y_IUnknownImpl_h_
+#define mozilla_a11y_IUnknownImpl_h_
+
+#include <windows.h>
+#undef CreateEvent // thank you windows you're such a helper
+#include "nsError.h"
+
+// Avoid warning C4509 like "nonstandard extension used:
+// 'AccessibleWrap::[acc_getName]' uses SEH and 'name' has destructor.
+// At this point we're catching a crash which is of much greater
+// importance than the missing dereference for the nsCOMPtr<>
+#ifdef _MSC_VER
+#pragma warning( disable : 4509 )
+#endif
+
+#ifdef __GNUC__
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+#else
+#define ATTRIBUTE_UNUSED
+#endif
+
+namespace mozilla {
+namespace a11y {
+
+class AutoRefCnt
+{
+public:
+ AutoRefCnt() : mValue(0) {}
+
+ ULONG operator++() { return ++mValue; }
+ ULONG operator--() { return --mValue; }
+ ULONG operator++(int) { return ++mValue; }
+ ULONG operator--(int) { return --mValue; }
+
+ operator ULONG() const { return mValue; }
+
+private:
+ ULONG mValue;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#define DECL_IUNKNOWN \
+public: \
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**); \
+ virtual ULONG STDMETHODCALLTYPE AddRef() final \
+ { \
+ MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
+ ++mRefCnt; \
+ return mRefCnt; \
+ } \
+ virtual ULONG STDMETHODCALLTYPE Release() final \
+ { \
+ MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
+ --mRefCnt; \
+ if (mRefCnt) \
+ return mRefCnt; \
+ \
+ delete this; \
+ return 0; \
+ } \
+private: \
+ mozilla::a11y::AutoRefCnt mRefCnt; \
+public:
+
+#define DECL_IUNKNOWN_INHERITED \
+public: \
+virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**); \
+
+#define IMPL_IUNKNOWN_QUERY_HEAD(Class) \
+STDMETHODIMP \
+Class::QueryInterface(REFIID aIID, void** aInstancePtr) \
+{ \
+ A11Y_TRYBLOCK_BEGIN \
+ if (!aInstancePtr) \
+ return E_INVALIDARG; \
+ *aInstancePtr = nullptr; \
+ \
+ HRESULT hr ATTRIBUTE_UNUSED = E_NOINTERFACE;
+
+#define IMPL_IUNKNOWN_QUERY_TAIL \
+ return hr; \
+ A11Y_TRYBLOCK_END \
+}
+
+#define IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(Member) \
+ return Member->QueryInterface(aIID, aInstancePtr); \
+ A11Y_TRYBLOCK_END \
+}
+
+#define IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(BaseClass) \
+ return BaseClass::QueryInterface(aIID, aInstancePtr); \
+ A11Y_TRYBLOCK_END \
+}
+
+#define IMPL_IUNKNOWN_QUERY_IFACE(Iface) \
+ if (aIID == IID_##Iface) { \
+ *aInstancePtr = static_cast<Iface*>(this); \
+ AddRef(); \
+ return S_OK; \
+ }
+
+#define IMPL_IUNKNOWN_QUERY_IFACE_AMBIGIOUS(Iface, aResolveIface) \
+ if (aIID == IID_##Iface) { \
+ *aInstancePtr = static_cast<Iface*>(static_cast<aResolveIface*>(this)); \
+ AddRef(); \
+ return S_OK; \
+ }
+
+#define IMPL_IUNKNOWN_QUERY_CLASS(Class) \
+ hr = Class::QueryInterface(aIID, aInstancePtr); \
+ if (SUCCEEDED(hr)) \
+ return hr;
+
+#define IMPL_IUNKNOWN_QUERY_CLASS_COND(Class, Cond) \
+ if (Cond) { \
+ hr = Class::QueryInterface(aIID, aInstancePtr); \
+ if (SUCCEEDED(hr)) \
+ return hr; \
+ }
+
+#define IMPL_IUNKNOWN_QUERY_AGGR_COND(Member, Cond) \
+ if (Cond) { \
+ hr = Member->QueryInterface(aIID, aInstancePtr); \
+ if (SUCCEEDED(hr)) \
+ return hr; \
+ }
+
+#define IMPL_IUNKNOWN1(Class, I1) \
+ IMPL_IUNKNOWN_QUERY_HEAD(Class) \
+ IMPL_IUNKNOWN_QUERY_IFACE(I1); \
+ IMPL_IUNKNOWN_QUERY_IFACE(IUnknown); \
+ IMPL_IUNKNOWN_QUERY_TAIL \
+
+#define IMPL_IUNKNOWN2(Class, I1, I2) \
+ IMPL_IUNKNOWN_QUERY_HEAD(Class) \
+ IMPL_IUNKNOWN_QUERY_IFACE(I1); \
+ IMPL_IUNKNOWN_QUERY_IFACE(I2); \
+ IMPL_IUNKNOWN_QUERY_IFACE_AMBIGIOUS(IUnknown, I1); \
+ IMPL_IUNKNOWN_QUERY_TAIL \
+
+#define IMPL_IUNKNOWN_INHERITED1(Class, Super0, Super1) \
+ IMPL_IUNKNOWN_QUERY_HEAD(Class) \
+ IMPL_IUNKNOWN_QUERY_CLASS(Super1); \
+ IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(Super0)
+
+#define IMPL_IUNKNOWN_INHERITED2(Class, Super0, Super1, Super2) \
+ IMPL_IUNKNOWN_QUERY_HEAD(Class) \
+ IMPL_IUNKNOWN_QUERY_CLASS(Super1); \
+ IMPL_IUNKNOWN_QUERY_CLASS(Super2); \
+ IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(Super0)
+
+
+/**
+ * Wrap every method body by these macroses to pass exception to the crash
+ * reporter.
+ */
+#define A11Y_TRYBLOCK_BEGIN \
+ MOZ_SEH_TRY {
+
+#define A11Y_TRYBLOCK_END \
+ } MOZ_SEH_EXCEPT(mozilla::a11y::FilterExceptions(::GetExceptionCode(), \
+ GetExceptionInformation())) \
+ { } \
+ return E_FAIL;
+
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * Converts nsresult to HRESULT.
+ */
+HRESULT GetHRESULT(nsresult aResult);
+
+/**
+ * Used to pass an exception to the crash reporter.
+ */
+int FilterExceptions(unsigned int aCode, EXCEPTION_POINTERS* aExceptionInfo);
+
+} // namespace a11y;
+} //namespace mozilla;
+
+#endif
diff --git a/accessible/windows/msaa/ImageAccessibleWrap.cpp b/accessible/windows/msaa/ImageAccessibleWrap.cpp
new file mode 100644
index 000000000..7ff2e8a47
--- /dev/null
+++ b/accessible/windows/msaa/ImageAccessibleWrap.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ImageAccessibleWrap.h"
+#include "nsIURI.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+NS_IMPL_ISUPPORTS_INHERITED0(ImageAccessibleWrap,
+ ImageAccessible)
+
+IMPL_IUNKNOWN_INHERITED1(ImageAccessibleWrap,
+ AccessibleWrap,
+ ia2AccessibleImage)
+
diff --git a/accessible/windows/msaa/ImageAccessibleWrap.h b/accessible/windows/msaa/ImageAccessibleWrap.h
new file mode 100644
index 000000000..e6a916ebe
--- /dev/null
+++ b/accessible/windows/msaa/ImageAccessibleWrap.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_ImageAccessibleWrap_h__
+#define mozilla_a11y_ImageAccessibleWrap_h__
+
+#include "ImageAccessible.h"
+#include "ia2AccessibleImage.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ImageAccessibleWrap : public ImageAccessible,
+ public ia2AccessibleImage
+{
+public:
+ ImageAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ ImageAccessible(aContent, aDoc) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+protected:
+ ~ImageAccessibleWrap() {}
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
+
diff --git a/accessible/windows/msaa/MsaaIdGenerator.cpp b/accessible/windows/msaa/MsaaIdGenerator.cpp
new file mode 100644
index 000000000..5f4b333fa
--- /dev/null
+++ b/accessible/windows/msaa/MsaaIdGenerator.cpp
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MsaaIdGenerator.h"
+
+#include "mozilla/a11y/AccessibleWrap.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/Unused.h"
+#include "nsDataHashtable.h"
+#include "nsIXULRuntime.h"
+
+// These constants may be adjusted to modify the proportion of the Child ID
+// allocated to the content ID vs proportion allocated to the unique ID. They
+// must always sum to 31, ie. the width of a 32-bit integer less the sign bit.
+
+// NB: kNumContentProcessIDBits must be large enough to successfully hold the
+// maximum permitted number of e10s content processes. If the e10s maximum
+// number of content processes changes, then kNumContentProcessIDBits must also
+// be updated if necessary to accommodate that new value!
+static const uint32_t kNumContentProcessIDBits = 7UL;
+static const uint32_t kNumUniqueIDBits = (31UL - kNumContentProcessIDBits);
+
+static_assert(kNumContentProcessIDBits + kNumUniqueIDBits == 31,
+ "Allocation of Content ID bits and Unique ID bits must sum to 31");
+
+namespace mozilla {
+namespace a11y {
+namespace detail {
+
+typedef nsDataHashtable<nsUint64HashKey, uint32_t> ContentParentIdMap;
+
+#pragma pack(push, 1)
+union MsaaID
+{
+ int32_t mInt32;
+ uint32_t mUInt32;
+ struct
+ {
+ uint32_t mUniqueID:kNumUniqueIDBits;
+ uint32_t mContentProcessID:kNumContentProcessIDBits;
+ uint32_t mSignBit:1;
+ }
+ mCracked;
+};
+#pragma pack(pop)
+
+static uint32_t
+BuildMsaaID(const uint32_t aID, const uint32_t aContentProcessID)
+{
+ MsaaID id;
+ id.mCracked.mSignBit = 0;
+ id.mCracked.mUniqueID = aID;
+ id.mCracked.mContentProcessID = aContentProcessID;
+ return ~id.mUInt32;
+}
+
+class MsaaIDCracker
+{
+public:
+ explicit MsaaIDCracker(const uint32_t aMsaaID)
+ {
+ mID.mUInt32 = ~aMsaaID;
+ }
+
+ uint32_t GetContentProcessId()
+ {
+ return mID.mCracked.mContentProcessID;
+ }
+
+ uint32_t GetUniqueId()
+ {
+ return mID.mCracked.mUniqueID;
+ }
+
+private:
+ MsaaID mID;
+};
+
+} // namespace detail
+
+constexpr MsaaIdGenerator::MsaaIdGenerator()
+ : mIDSet(kNumUniqueIDBits)
+{}
+
+uint32_t
+MsaaIdGenerator::GetID()
+{
+ uint32_t id = mIDSet.GetID();
+ MOZ_ASSERT(id <= ((1UL << kNumUniqueIDBits) - 1UL));
+ return detail::BuildMsaaID(id, ResolveContentProcessID());
+}
+
+void
+MsaaIdGenerator::ReleaseID(AccessibleWrap* aAccWrap)
+{
+ MOZ_ASSERT(aAccWrap);
+ uint32_t id = aAccWrap->GetExistingID();
+ MOZ_ASSERT(id != AccessibleWrap::kNoID);
+ detail::MsaaIDCracker cracked(id);
+ if (cracked.GetContentProcessId() != ResolveContentProcessID()) {
+ // This may happen if chrome holds a proxy whose ID was originally generated
+ // by a content process. Since ReleaseID only has meaning in the process
+ // that originally generated that ID, we ignore ReleaseID calls for any ID
+ // that did not come from the current process.
+ MOZ_ASSERT(aAccWrap->IsProxy());
+ return;
+ }
+ mIDSet.ReleaseID(cracked.GetUniqueId());
+}
+
+bool
+MsaaIdGenerator::IsChromeID(uint32_t aID)
+{
+ detail::MsaaIDCracker cracked(aID);
+ return cracked.GetContentProcessId() == 0;
+}
+
+bool
+MsaaIdGenerator::IsIDForThisContentProcess(uint32_t aID)
+{
+ MOZ_ASSERT(XRE_IsContentProcess());
+ detail::MsaaIDCracker cracked(aID);
+ return cracked.GetContentProcessId() == ResolveContentProcessID();
+}
+
+bool
+MsaaIdGenerator::IsIDForContentProcess(uint32_t aID,
+ dom::ContentParentId aIPCContentProcessId)
+{
+ MOZ_ASSERT(XRE_IsParentProcess());
+ detail::MsaaIDCracker cracked(aID);
+ return cracked.GetContentProcessId() ==
+ GetContentProcessIDFor(aIPCContentProcessId);
+}
+
+bool
+MsaaIdGenerator::IsSameContentProcessFor(uint32_t aFirstID, uint32_t aSecondID)
+{
+ detail::MsaaIDCracker firstCracked(aFirstID);
+ detail::MsaaIDCracker secondCracked(aSecondID);
+ return firstCracked.GetContentProcessId() ==
+ secondCracked.GetContentProcessId();
+}
+
+uint32_t
+MsaaIdGenerator::ResolveContentProcessID()
+{
+ if (XRE_IsParentProcess()) {
+ return 0;
+ }
+
+ dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
+ uint32_t result = contentChild->GetMsaaID();
+
+ MOZ_ASSERT(result);
+ return result;
+}
+
+/**
+ * Each dom::ContentParent has a 64-bit ID. This ID is monotonically increasing
+ * with each new content process, so those IDs are effectively single-use. OTOH,
+ * MSAA requires 32-bit IDs. Since we only allocate kNumContentProcessIDBits for
+ * the content process ID component, the MSAA content process ID value must be
+ * reusable. sContentParentIdMap holds the current associations between
+ * dom::ContentParent IDs and the MSAA content parent IDs that have been
+ * allocated to them.
+ */
+static StaticAutoPtr<detail::ContentParentIdMap> sContentParentIdMap;
+
+static const uint32_t kBitsPerByte = 8UL;
+// Set sContentProcessIdBitmap[0] to 1 to reserve the Chrome process's id
+static uint64_t sContentProcessIdBitmap[(1UL << kNumContentProcessIDBits) /
+ (sizeof(uint64_t) * kBitsPerByte)] = {1ULL};
+static const uint32_t kBitsPerElement = sizeof(sContentProcessIdBitmap[0]) *
+ kBitsPerByte;
+
+uint32_t
+MsaaIdGenerator::GetContentProcessIDFor(dom::ContentParentId aIPCContentProcessID)
+{
+ MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
+ if (!sContentParentIdMap) {
+ sContentParentIdMap = new detail::ContentParentIdMap();
+ ClearOnShutdown(&sContentParentIdMap);
+ }
+
+ uint32_t value = 0;
+ if (sContentParentIdMap->Get(aIPCContentProcessID, &value)) {
+ return value;
+ }
+
+ uint32_t index = 0;
+ for (; index < ArrayLength(sContentProcessIdBitmap); ++index) {
+ if (sContentProcessIdBitmap[index] == UINT64_MAX) {
+ continue;
+ }
+ uint32_t bitIndex = CountTrailingZeroes64(~sContentProcessIdBitmap[index]);
+ MOZ_ASSERT(!(sContentProcessIdBitmap[index] & (1ULL << bitIndex)));
+ MOZ_ASSERT(bitIndex != 0 || index != 0);
+ sContentProcessIdBitmap[index] |= (1ULL << bitIndex);
+ value = index * kBitsPerElement + bitIndex;
+ break;
+ }
+
+ // If we run out of content process IDs, we're in trouble
+ MOZ_RELEASE_ASSERT(index < ArrayLength(sContentProcessIdBitmap));
+
+ sContentParentIdMap->Put(aIPCContentProcessID, value);
+ return value;
+}
+
+void
+MsaaIdGenerator::ReleaseContentProcessIDFor(dom::ContentParentId aIPCContentProcessID)
+{
+ MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
+ if (!sContentParentIdMap) {
+ // Since Content IDs are generated lazily, ContentParent might attempt
+ // to release an ID that was never allocated to begin with.
+ return;
+ }
+
+ Maybe<uint32_t> mapping = sContentParentIdMap->GetAndRemove(aIPCContentProcessID);
+ if (!mapping) {
+ // Since Content IDs are generated lazily, ContentParent might attempt
+ // to release an ID that was never allocated to begin with.
+ return;
+ }
+
+ uint32_t index = mapping.ref() / kBitsPerElement;
+ MOZ_ASSERT(index < ArrayLength(sContentProcessIdBitmap));
+
+ uint64_t mask = 1ULL << (mapping.ref() % kBitsPerElement);
+ MOZ_ASSERT(sContentProcessIdBitmap[index] & mask);
+
+ sContentProcessIdBitmap[index] &= ~mask;
+}
+
+} // namespace a11y
+} // namespace mozilla
diff --git a/accessible/windows/msaa/MsaaIdGenerator.h b/accessible/windows/msaa/MsaaIdGenerator.h
new file mode 100644
index 000000000..b845e8473
--- /dev/null
+++ b/accessible/windows/msaa/MsaaIdGenerator.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_MsaaIdGenerator_h
+#define mozilla_a11y_MsaaIdGenerator_h
+
+#include "mozilla/a11y/IDSet.h"
+
+#include "mozilla/dom/ipc/IdType.h"
+
+namespace mozilla {
+namespace a11y {
+
+class AccessibleWrap;
+
+/**
+ * This class is responsible for generating child IDs used by our MSAA
+ * implementation. Since e10s requires us to differentiate IDs based on the
+ * originating process of the accessible, a portion of the ID's bits are
+ * allocated to storing that information. The remaining bits represent the
+ * unique ID of the accessible, within that content process.
+ *
+ * The constants kNumContentProcessIDBits and kNumUniqueIDBits in the
+ * implementation are responsible for determining the proportion of bits that
+ * are allocated for each purpose.
+ */
+class MsaaIdGenerator
+{
+public:
+ constexpr MsaaIdGenerator();
+
+ uint32_t GetID();
+ void ReleaseID(AccessibleWrap* aAccWrap);
+ bool IsChromeID(uint32_t aID);
+ bool IsIDForThisContentProcess(uint32_t aID);
+ bool IsIDForContentProcess(uint32_t aID,
+ dom::ContentParentId aIPCContentProcessId);
+ bool IsSameContentProcessFor(uint32_t aFirstID, uint32_t aSecondID);
+
+ uint32_t GetContentProcessIDFor(dom::ContentParentId aIPCContentProcessID);
+ void ReleaseContentProcessIDFor(dom::ContentParentId aIPCContentProcessID);
+
+private:
+ uint32_t ResolveContentProcessID();
+
+private:
+ IDSet mIDSet;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // mozilla_a11y_MsaaIdGenerator_h
diff --git a/accessible/windows/msaa/Platform.cpp b/accessible/windows/msaa/Platform.cpp
new file mode 100644
index 000000000..dc6acd3ad
--- /dev/null
+++ b/accessible/windows/msaa/Platform.cpp
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Platform.h"
+
+#include "AccEvent.h"
+#include "Compatibility.h"
+#include "HyperTextAccessibleWrap.h"
+#include "ia2AccessibleText.h"
+#include "nsIXULRuntime.h"
+#include "nsWinUtils.h"
+#include "mozilla/a11y/ProxyAccessible.h"
+#include "mozilla/mscom/InterceptorLog.h"
+#include "mozilla/mscom/Registration.h"
+#include "mozilla/StaticPtr.h"
+#include "ProxyWrappers.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+using namespace mozilla::mscom;
+
+static StaticAutoPtr<RegisteredProxy> gRegProxy;
+static StaticAutoPtr<RegisteredProxy> gRegAccTlb;
+static StaticAutoPtr<RegisteredProxy> gRegMiscTlb;
+
+void
+a11y::PlatformInit()
+{
+ Compatibility::Init();
+
+ nsWinUtils::MaybeStartWindowEmulation();
+ ia2AccessibleText::InitTextChangeData();
+ if (BrowserTabsRemoteAutostart()) {
+ mscom::InterceptorLog::Init();
+ UniquePtr<RegisteredProxy> regProxy(
+ mscom::RegisterProxy(L"ia2marshal.dll"));
+ gRegProxy = regProxy.release();
+ UniquePtr<RegisteredProxy> regAccTlb(
+ mscom::RegisterTypelib(L"oleacc.dll",
+ RegistrationFlags::eUseSystemDirectory));
+ gRegAccTlb = regAccTlb.release();
+ UniquePtr<RegisteredProxy> regMiscTlb(
+ mscom::RegisterTypelib(L"Accessible.tlb"));
+ gRegMiscTlb = regMiscTlb.release();
+ }
+}
+
+void
+a11y::PlatformShutdown()
+{
+ ::DestroyCaret();
+
+ nsWinUtils::ShutdownWindowEmulation();
+ gRegProxy = nullptr;
+ gRegAccTlb = nullptr;
+ gRegMiscTlb = nullptr;
+}
+
+void
+a11y::ProxyCreated(ProxyAccessible* aProxy, uint32_t aInterfaces)
+{
+ AccessibleWrap* wrapper = nullptr;
+ if (aInterfaces & Interfaces::DOCUMENT) {
+ wrapper = new DocProxyAccessibleWrap(aProxy);
+ } else if (aInterfaces & Interfaces::HYPERTEXT) {
+ wrapper = new HyperTextProxyAccessibleWrap(aProxy);
+ } else {
+ wrapper = new ProxyAccessibleWrap(aProxy);
+ }
+
+ wrapper->SetProxyInterfaces(aInterfaces);
+ wrapper->AddRef();
+ aProxy->SetWrapper(reinterpret_cast<uintptr_t>(wrapper));
+}
+
+void
+a11y::ProxyDestroyed(ProxyAccessible* aProxy)
+{
+ AccessibleWrap* wrapper =
+ reinterpret_cast<AccessibleWrap*>(aProxy->GetWrapper());
+ MOZ_ASSERT(wrapper);
+ if (!wrapper)
+ return;
+
+ wrapper->Shutdown();
+ aProxy->SetWrapper(0);
+ wrapper->Release();
+}
+
+void
+a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType)
+{
+ AccessibleWrap::FireWinEvent(WrapperFor(aTarget), aEventType);
+}
+
+void
+a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t, bool)
+{
+ AccessibleWrap::FireWinEvent(WrapperFor(aTarget),
+ nsIAccessibleEvent::EVENT_STATE_CHANGE);
+}
+
+void
+a11y::ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset)
+{
+ AccessibleWrap::FireWinEvent(WrapperFor(aTarget),
+ nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED);
+}
+
+void
+a11y::ProxyTextChangeEvent(ProxyAccessible* aText, const nsString& aStr,
+ int32_t aStart, uint32_t aLen, bool aInsert, bool)
+{
+ AccessibleWrap* wrapper = WrapperFor(aText);
+ MOZ_ASSERT(wrapper);
+ if (!wrapper) {
+ return;
+ }
+
+ auto text = static_cast<HyperTextAccessibleWrap*>(wrapper->AsHyperText());
+ if (text) {
+ ia2AccessibleText::UpdateTextChangeData(text, aInsert, aStr, aStart, aLen);
+ }
+
+ uint32_t eventType = aInsert ? nsIAccessibleEvent::EVENT_TEXT_INSERTED :
+ nsIAccessibleEvent::EVENT_TEXT_REMOVED;
+ AccessibleWrap::FireWinEvent(wrapper, eventType);
+}
+
+void
+a11y::ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible*, bool aInsert, bool)
+{
+ uint32_t event = aInsert ? nsIAccessibleEvent::EVENT_SHOW :
+ nsIAccessibleEvent::EVENT_HIDE;
+ AccessibleWrap* wrapper = WrapperFor(aTarget);
+ AccessibleWrap::FireWinEvent(wrapper, event);
+}
+
+void
+a11y::ProxySelectionEvent(ProxyAccessible* aTarget, ProxyAccessible*, uint32_t aType)
+{
+ AccessibleWrap* wrapper = WrapperFor(aTarget);
+ AccessibleWrap::FireWinEvent(wrapper, aType);
+}
diff --git a/accessible/windows/msaa/RootAccessibleWrap.cpp b/accessible/windows/msaa/RootAccessibleWrap.cpp
new file mode 100644
index 000000000..30fe40c43
--- /dev/null
+++ b/accessible/windows/msaa/RootAccessibleWrap.cpp
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RootAccessibleWrap.h"
+
+#include "Compatibility.h"
+#include "nsCoreUtils.h"
+#include "nsWinUtils.h"
+
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// Constructor/destructor
+
+RootAccessibleWrap::
+ RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+ RootAccessible(aDocument, aPresShell)
+{
+}
+
+RootAccessibleWrap::~RootAccessibleWrap()
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RootAccessible
+
+void
+RootAccessibleWrap::DocumentActivated(DocAccessible* aDocument)
+{
+ if (Compatibility::IsDolphin() &&
+ nsCoreUtils::IsTabDocument(aDocument->DocumentNode())) {
+ uint32_t count = mChildDocuments.Length();
+ for (uint32_t idx = 0; idx < count; idx++) {
+ DocAccessible* childDoc = mChildDocuments[idx];
+ HWND childDocHWND = static_cast<HWND>(childDoc->GetNativeWindow());
+ if (childDoc != aDocument)
+ nsWinUtils::HideNativeWindow(childDocHWND);
+ else
+ nsWinUtils::ShowNativeWindow(childDocHWND);
+ }
+ }
+}
diff --git a/accessible/windows/msaa/RootAccessibleWrap.h b/accessible/windows/msaa/RootAccessibleWrap.h
new file mode 100644
index 000000000..6aa6fefe3
--- /dev/null
+++ b/accessible/windows/msaa/RootAccessibleWrap.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_RootAccessibleWrap_h__
+#define mozilla_a11y_RootAccessibleWrap_h__
+
+#include "RootAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+class RootAccessibleWrap : public RootAccessible
+{
+public:
+ RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+ virtual ~RootAccessibleWrap();
+
+ // RootAccessible
+ virtual void DocumentActivated(DocAccessible* aDocument);
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/msaa/ServiceProvider.cpp b/accessible/windows/msaa/ServiceProvider.cpp
new file mode 100644
index 000000000..82265d3c2
--- /dev/null
+++ b/accessible/windows/msaa/ServiceProvider.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ServiceProvider.h"
+
+#include "ApplicationAccessibleWrap.h"
+#include "Compatibility.h"
+#include "DocAccessible.h"
+#include "nsAccUtils.h"
+#include "nsCoreUtils.h"
+#include "Relation.h"
+#include "uiaRawElmProvider.h"
+
+#include "mozilla/Preferences.h"
+#include "nsIDocShell.h"
+
+#include "ISimpleDOMNode_i.c"
+
+namespace mozilla {
+namespace a11y {
+
+IMPL_IUNKNOWN_QUERY_HEAD(ServiceProvider)
+ IMPL_IUNKNOWN_QUERY_IFACE(IServiceProvider)
+IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mAccessible)
+
+
+////////////////////////////////////////////////////////////////////////////////
+// IServiceProvider
+
+STDMETHODIMP
+ServiceProvider::QueryService(REFGUID aGuidService, REFIID aIID,
+ void** aInstancePtr)
+{
+ if (!aInstancePtr)
+ return E_INVALIDARG;
+
+ *aInstancePtr = nullptr;
+
+ // UIA IAccessibleEx
+ if (aGuidService == IID_IAccessibleEx &&
+ Preferences::GetBool("accessibility.uia.enable")) {
+ uiaRawElmProvider* accEx = new uiaRawElmProvider(mAccessible);
+ HRESULT hr = accEx->QueryInterface(aIID, aInstancePtr);
+ if (FAILED(hr))
+ delete accEx;
+
+ return hr;
+ }
+
+ // Provide a special service ID for getting the accessible for the browser tab
+ // document that contains this accessible object. If this accessible object
+ // is not inside a browser tab then the service fails with E_NOINTERFACE.
+ // A use case for this is for screen readers that need to switch context or
+ // 'virtual buffer' when focus moves from one browser tab area to another.
+ static const GUID SID_IAccessibleContentDocument =
+ { 0xa5d8e1f3,0x3571,0x4d8f,{0x95,0x21,0x07,0xed,0x28,0xfb,0x07,0x2e} };
+ if (aGuidService == SID_IAccessibleContentDocument) {
+ if (aIID != IID_IAccessible)
+ return E_NOINTERFACE;
+
+ Relation rel = mAccessible->RelationByType(RelationType::CONTAINING_TAB_PANE);
+ AccessibleWrap* tabDoc = static_cast<AccessibleWrap*>(rel.Next());
+ if (!tabDoc)
+ return E_NOINTERFACE;
+
+ *aInstancePtr = static_cast<IAccessible*>(tabDoc);
+ (reinterpret_cast<IUnknown*>(*aInstancePtr))->AddRef();
+ return S_OK;
+ }
+
+ // Can get to IAccessibleApplication from any node via QS
+ if (aGuidService == IID_IAccessibleApplication ||
+ (Compatibility::IsJAWS() && aIID == IID_IAccessibleApplication)) {
+ ApplicationAccessibleWrap* applicationAcc =
+ static_cast<ApplicationAccessibleWrap*>(ApplicationAcc());
+ if (!applicationAcc)
+ return E_NOINTERFACE;
+
+ return applicationAcc->QueryInterface(aIID, aInstancePtr);
+ }
+
+ static const GUID IID_SimpleDOMDeprecated =
+ { 0x0c539790,0x12e4,0x11cf,{0xb6,0x61,0x00,0xaa,0x00,0x4c,0xd6,0xd8} };
+ if (aGuidService == IID_ISimpleDOMNode ||
+ aGuidService == IID_SimpleDOMDeprecated ||
+ aGuidService == IID_IAccessible || aGuidService == IID_IAccessible2)
+ return mAccessible->QueryInterface(aIID, aInstancePtr);
+
+ return E_INVALIDARG;
+}
+
+} // namespace a11y
+} // namespace mozilla
diff --git a/accessible/windows/msaa/ServiceProvider.h b/accessible/windows/msaa/ServiceProvider.h
new file mode 100644
index 000000000..b0fc812c5
--- /dev/null
+++ b/accessible/windows/msaa/ServiceProvider.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_ServiceProvider_h_
+#define mozilla_a11y_ServiceProvider_h_
+
+#include <servprov.h>
+
+#include "AccessibleWrap.h"
+#include "IUnknownImpl.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ServiceProvider final : public IServiceProvider
+{
+public:
+ ServiceProvider(AccessibleWrap* aAcc) : mAccessible(aAcc) {}
+ ~ServiceProvider() {}
+
+ DECL_IUNKNOWN
+
+ // IServiceProvider
+ virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID aGuidService,
+ REFIID aIID,
+ void** aInstancePtr);
+
+private:
+ RefPtr<AccessibleWrap> mAccessible;
+};
+
+}
+}
+
+#endif
diff --git a/accessible/windows/msaa/TextLeafAccessibleWrap.cpp b/accessible/windows/msaa/TextLeafAccessibleWrap.cpp
new file mode 100644
index 000000000..6f1d193db
--- /dev/null
+++ b/accessible/windows/msaa/TextLeafAccessibleWrap.cpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TextLeafAccessibleWrap.h"
+
+#include "sdnTextAccessible.h"
+#include "Statistics.h"
+
+using namespace mozilla::a11y;
+
+IMPL_IUNKNOWN_QUERY_HEAD(TextLeafAccessibleWrap)
+ if (aIID == IID_ISimpleDOMText) {
+ statistics::ISimpleDOMUsed();
+ *aInstancePtr = static_cast<ISimpleDOMText*>(new sdnTextAccessible(this));
+ static_cast<IUnknown*>(*aInstancePtr)->AddRef();
+ return S_OK;
+ }
+IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(AccessibleWrap)
diff --git a/accessible/windows/msaa/TextLeafAccessibleWrap.h b/accessible/windows/msaa/TextLeafAccessibleWrap.h
new file mode 100644
index 000000000..612bed173
--- /dev/null
+++ b/accessible/windows/msaa/TextLeafAccessibleWrap.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_TextLeafAccessibleWrap_h__
+#define mozilla_a11y_TextLeafAccessibleWrap_h__
+
+#include "TextLeafAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * Wrap TextLeafAccessible to expose ISimpleDOMText as a native interface with
+ * a tear off.
+ */
+class TextLeafAccessibleWrap : public TextLeafAccessible
+{
+public:
+ TextLeafAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ TextLeafAccessible(aContent, aDoc) { }
+ virtual ~TextLeafAccessibleWrap() {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/msaa/XULListboxAccessibleWrap.cpp b/accessible/windows/msaa/XULListboxAccessibleWrap.cpp
new file mode 100644
index 000000000..4bd0fb512
--- /dev/null
+++ b/accessible/windows/msaa/XULListboxAccessibleWrap.cpp
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "XULListboxAccessibleWrap.h"
+
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// XULListboxAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(XULListboxAccessibleWrap,
+ XULListboxAccessible)
+
+IMPL_IUNKNOWN_QUERY_HEAD(XULListboxAccessibleWrap)
+IMPL_IUNKNOWN_QUERY_CLASS_COND(ia2AccessibleTable,
+ !IsDefunct() && IsMulticolumn());
+IMPL_IUNKNOWN_QUERY_CLASS(AccessibleWrap)
+IMPL_IUNKNOWN_QUERY_TAIL
+
+void
+XULListboxAccessibleWrap::Shutdown()
+{
+ ia2AccessibleTable::mTable = nullptr;
+ XULListboxAccessible::Shutdown();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// XULListCellAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(XULListCellAccessibleWrap,
+ XULListCellAccessible)
+
+IMPL_IUNKNOWN_INHERITED1(XULListCellAccessibleWrap,
+ HyperTextAccessibleWrap,
+ ia2AccessibleTableCell)
+
+void
+XULListCellAccessibleWrap::Shutdown()
+{
+ ia2AccessibleTableCell::mTableCell = nullptr;
+ XULListCellAccessible::Shutdown();
+}
diff --git a/accessible/windows/msaa/XULListboxAccessibleWrap.h b/accessible/windows/msaa/XULListboxAccessibleWrap.h
new file mode 100644
index 000000000..37db2d70a
--- /dev/null
+++ b/accessible/windows/msaa/XULListboxAccessibleWrap.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_XULListboxAccessibleWrap_h__
+#define mozilla_a11y_XULListboxAccessibleWrap_h__
+
+#include "XULListboxAccessible.h"
+
+#include "ia2AccessibleTable.h"
+#include "ia2AccessibleTableCell.h"
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * IA2 wrapper class for XULListboxAccessible class implementing
+ * IAccessibleTable and IAccessibleTable2 interfaces.
+ */
+class XULListboxAccessibleWrap : public XULListboxAccessible,
+ public ia2AccessibleTable
+{
+ ~XULListboxAccessibleWrap() {}
+
+public:
+ XULListboxAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ XULListboxAccessible(aContent, aDoc), ia2AccessibleTable(this) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ virtual void Shutdown() override;
+};
+
+/**
+ * IA2 wrapper class for XULListCellAccessible class, implements
+ * IAccessibleTableCell interface.
+ */
+class XULListCellAccessibleWrap : public XULListCellAccessible,
+ public ia2AccessibleTableCell
+{
+ ~XULListCellAccessibleWrap() {}
+
+public:
+ XULListCellAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ XULListCellAccessible(aContent, aDoc), ia2AccessibleTableCell(this) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ virtual void Shutdown() override;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/msaa/XULMenuAccessibleWrap.cpp b/accessible/windows/msaa/XULMenuAccessibleWrap.cpp
new file mode 100644
index 000000000..ba0075bac
--- /dev/null
+++ b/accessible/windows/msaa/XULMenuAccessibleWrap.cpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "XULMenuAccessibleWrap.h"
+#include "nsNameSpaceManager.h"
+
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// XULMenuAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+XULMenuitemAccessibleWrap::
+ XULMenuitemAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ XULMenuitemAccessible(aContent, aDoc)
+{
+}
+
+ENameValueFlag
+XULMenuitemAccessibleWrap::Name(nsString& aName)
+{
+ // XXX This should be done in MSAA's get_accName() so that Accessible::Name()]
+ // provides the same results on all platforms
+ XULMenuitemAccessible::Name(aName);
+ if (aName.IsEmpty())
+ return eNameOK;
+
+ nsAutoString accel;
+ mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accel);
+ if (!accel.IsEmpty())
+ aName += NS_LITERAL_STRING("\t") + accel;
+
+ return eNameOK;
+}
diff --git a/accessible/windows/msaa/XULMenuAccessibleWrap.h b/accessible/windows/msaa/XULMenuAccessibleWrap.h
new file mode 100644
index 000000000..a07182241
--- /dev/null
+++ b/accessible/windows/msaa/XULMenuAccessibleWrap.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_XULMenuAccessibleWrap_h__
+#define mozilla_a11y_XULMenuAccessibleWrap_h__
+
+#include "XULMenuAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+class XULMenuitemAccessibleWrap : public XULMenuitemAccessible
+{
+public:
+ XULMenuitemAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc);
+ virtual ~XULMenuitemAccessibleWrap() {}
+
+ // nsIAccessible
+ virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/msaa/XULTreeGridAccessibleWrap.cpp b/accessible/windows/msaa/XULTreeGridAccessibleWrap.cpp
new file mode 100644
index 000000000..e5cc4a09b
--- /dev/null
+++ b/accessible/windows/msaa/XULTreeGridAccessibleWrap.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "XULTreeGridAccessibleWrap.h"
+
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// XULTreeGridAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(XULTreeGridAccessibleWrap,
+ XULTreeGridAccessible)
+
+IMPL_IUNKNOWN_INHERITED1(XULTreeGridAccessibleWrap,
+ AccessibleWrap,
+ ia2AccessibleTable)
+
+void
+XULTreeGridAccessibleWrap::Shutdown()
+{
+ ia2AccessibleTable::mTable = nullptr;
+ XULTreeGridAccessible::Shutdown();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// XULTreeGridCellAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(XULTreeGridCellAccessibleWrap,
+ XULTreeGridCellAccessible)
+
+IMPL_IUNKNOWN_INHERITED1(XULTreeGridCellAccessibleWrap,
+ AccessibleWrap,
+ ia2AccessibleTableCell)
+
+void
+XULTreeGridCellAccessibleWrap::Shutdown()
+{
+ ia2AccessibleTableCell::mTableCell = nullptr;
+ XULTreeGridCellAccessible::Shutdown();
+}
diff --git a/accessible/windows/msaa/XULTreeGridAccessibleWrap.h b/accessible/windows/msaa/XULTreeGridAccessibleWrap.h
new file mode 100644
index 000000000..3c6c62699
--- /dev/null
+++ b/accessible/windows/msaa/XULTreeGridAccessibleWrap.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_XULTreeGridAccessibleWrap_h__
+#define mozilla_a11y_XULTreeGridAccessibleWrap_h__
+
+#include "XULTreeGridAccessible.h"
+
+#include "ia2AccessibleTable.h"
+#include "ia2AccessibleTableCell.h"
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * IA2 wrapper class for XULTreeGridAccessible class implementing
+ * IAccessibleTable and IAccessibleTable2 interfaces.
+ */
+class XULTreeGridAccessibleWrap : public XULTreeGridAccessible,
+ public ia2AccessibleTable
+{
+ ~XULTreeGridAccessibleWrap() {}
+
+public:
+ XULTreeGridAccessibleWrap(nsIContent* aContent, DocAccessible* aDoc,
+ nsTreeBodyFrame* aTree) :
+ XULTreeGridAccessible(aContent, aDoc, aTree), ia2AccessibleTable(this) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ virtual void Shutdown() override;
+};
+
+/**
+ * IA2 wrapper class for XULTreeGridCellAccessible class, implements
+ * IAccessibleTableCell interface.
+ */
+class XULTreeGridCellAccessibleWrap : public XULTreeGridCellAccessible,
+ public ia2AccessibleTableCell
+{
+ ~XULTreeGridCellAccessibleWrap() {}
+
+public:
+ XULTreeGridCellAccessibleWrap(nsIContent* aContent,
+ DocAccessible* aDoc,
+ XULTreeGridRowAccessible* aRowAcc,
+ nsITreeBoxObject* aTree,
+ nsITreeView* aTreeView,
+ int32_t aRow, nsITreeColumn* aColumn) :
+ XULTreeGridCellAccessible(aContent, aDoc, aRowAcc, aTree, aTreeView, aRow,
+ aColumn), ia2AccessibleTableCell(this) {}
+
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ virtual void Shutdown() override;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/msaa/moz.build b/accessible/windows/msaa/moz.build
new file mode 100644
index 000000000..54c8c6686
--- /dev/null
+++ b/accessible/windows/msaa/moz.build
@@ -0,0 +1,76 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS += [
+ 'IUnknownImpl.h',
+]
+
+EXPORTS.mozilla.a11y += [
+ 'AccessibleWrap.h',
+ 'Compatibility.h',
+ 'HyperTextAccessibleWrap.h',
+ 'IDSet.h',
+ 'MsaaIdGenerator.h',
+]
+
+UNIFIED_SOURCES += [
+ 'AccessibleWrap.cpp',
+ 'ApplicationAccessibleWrap.cpp',
+ 'ARIAGridAccessibleWrap.cpp',
+ 'Compatibility.cpp',
+ 'DocAccessibleWrap.cpp',
+ 'EnumVariant.cpp',
+ 'HTMLTableAccessibleWrap.cpp',
+ 'HTMLWin32ObjectAccessible.cpp',
+ 'HyperTextAccessibleWrap.cpp',
+ 'ImageAccessibleWrap.cpp',
+ 'IUnknownImpl.cpp',
+ 'MsaaIdGenerator.cpp',
+ 'nsWinUtils.cpp',
+ 'Platform.cpp',
+ 'RootAccessibleWrap.cpp',
+ 'TextLeafAccessibleWrap.cpp',
+]
+
+# This file cannot be built in unified mode because it includes ISimpleDOMNode_i.c.
+SOURCES += [
+ 'ServiceProvider.cpp',
+]
+
+if CONFIG['MOZ_XUL']:
+ UNIFIED_SOURCES += [
+ 'XULListboxAccessibleWrap.cpp',
+ 'XULMenuAccessibleWrap.cpp',
+ 'XULTreeGridAccessibleWrap.cpp',
+ ]
+
+LOCAL_INCLUDES += [
+ '/accessible/base',
+ '/accessible/generic',
+ '/accessible/html',
+ '/accessible/ipc',
+ '/accessible/ipc/win',
+ '/accessible/windows',
+ '/accessible/windows/ia2',
+ '/accessible/windows/sdn',
+ '/accessible/windows/uia',
+ '/accessible/xpcom',
+ '/accessible/xul',
+ '/dom/base',
+ '/layout/style',
+]
+
+# The Windows MIDL code generator creates things like:
+#
+# #endif !_MIDL_USE_GUIDDEF_
+#
+# which clang-cl complains about. MSVC doesn't, so turn this warning off.
+if CONFIG['CLANG_CL']:
+ CXXFLAGS += ['-Wno-extra-tokens']
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
diff --git a/accessible/windows/msaa/nsEventMap.h b/accessible/windows/msaa/nsEventMap.h
new file mode 100644
index 000000000..8af992e1c
--- /dev/null
+++ b/accessible/windows/msaa/nsEventMap.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <winuser.h>
+#include "AccessibleEventId.h"
+
+const uint32_t kEVENT_WIN_UNKNOWN = 0x00000000;
+
+static const uint32_t gWinEventMap[] = {
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent doesn't have 0 constant
+ EVENT_OBJECT_SHOW, // nsIAccessibleEvent::EVENT_SHOW
+ EVENT_OBJECT_HIDE, // nsIAccessibleEvent::EVENT_HIDE
+ EVENT_OBJECT_REORDER, // nsIAccessibleEvent::EVENT_REORDER
+ IA2_EVENT_ACTIVE_DECENDENT_CHANGED, // nsIAccessibleEvent::EVENT_ACTIVE_DECENDENT_CHANGED
+ EVENT_OBJECT_FOCUS, // nsIAccessibleEvent::EVENT_FOCUS
+ EVENT_OBJECT_STATECHANGE, // nsIAccessibleEvent::EVENT_STATE_CHANGE
+ EVENT_OBJECT_LOCATIONCHANGE, // nsIAccessibleEvent::EVENT_LOCATION_CHANGE
+ EVENT_OBJECT_NAMECHANGE, // nsIAccessibleEvent::EVENT_NAME_CHANGE
+ EVENT_OBJECT_DESCRIPTIONCHANGE, // nsIAccessibleEvent::EVENT_DESCRIPTION_CHANGE
+ EVENT_OBJECT_VALUECHANGE, // nsIAccessibleEvent::EVENT_VALUE_CHANGE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_HELP_CHANGE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_DEFACTION_CHANGE
+ IA2_EVENT_ACTION_CHANGED, // nsIAccessibleEvent::EVENT_ACTION_CHANGE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_ACCELERATOR_CHANGE
+ EVENT_OBJECT_SELECTION, // nsIAccessibleEvent::EVENT_SELECTION
+ EVENT_OBJECT_SELECTIONADD, // nsIAccessibleEvent::EVENT_SELECTION_ADD
+ EVENT_OBJECT_SELECTIONREMOVE, // nsIAccessibleEvent::EVENT_SELECTION_REMOVE
+ EVENT_OBJECT_SELECTIONWITHIN, // nsIAccessibleEvent::EVENT_SELECTION_WITHIN
+ EVENT_SYSTEM_ALERT, // nsIAccessibleEvent::EVENT_ALERT
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_FOREGROUND
+ EVENT_SYSTEM_MENUSTART, // nsIAccessibleEvent::EVENT_MENU_START
+ EVENT_SYSTEM_MENUEND, // nsIAccessibleEvent::EVENT_MENU_END
+ EVENT_SYSTEM_MENUPOPUPSTART, // nsIAccessibleEvent::EVENT_MENUPOPUP_START
+ EVENT_SYSTEM_MENUPOPUPEND, // nsIAccessibleEvent::EVENT_MENUPOPUP_END
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_CAPTURE_START
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_CAPTURE_END
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_MOVESIZE_START
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_MOVESIZE_END
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_CONTEXT_HELP_START
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_CONTEXT_HELP_END
+ EVENT_SYSTEM_DRAGDROPSTART, // nsIAccessibleEvent::EVENT_DRAGDROP_START
+ EVENT_SYSTEM_DRAGDROPEND, // nsIAccessibleEvent::EVENT_DRAGDROP_END
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_DIALOG_START
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_DIALOG_END
+ EVENT_SYSTEM_SCROLLINGSTART, // nsIAccessibleEvent::EVENT_SCROLLING_START
+ EVENT_SYSTEM_SCROLLINGEND, // nsIAccessibleEvent::EVENT_SCROLLING_END
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_MINIMIZE_START
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_MINIMIZE_END
+ IA2_EVENT_DOCUMENT_LOAD_COMPLETE, // nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE
+ IA2_EVENT_DOCUMENT_RELOAD, // nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD
+ IA2_EVENT_DOCUMENT_LOAD_STOPPED, // nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED
+ IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED, // nsIAccessibleEvent::EVENT_DOCUMENT_ATTRIBUTES_CHANGED
+ IA2_EVENT_DOCUMENT_CONTENT_CHANGED, // nsIAccessibleEvent::EVENT_DOCUMENT_CONTENT_CHANGED
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_PROPERTY_CHANGED
+ IA2_EVENT_PAGE_CHANGED, // nsIAccessibleEvent::IA2_EVENT_PAGE_CHANGED
+ IA2_EVENT_TEXT_ATTRIBUTE_CHANGED, // nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED
+ IA2_EVENT_TEXT_CARET_MOVED, // nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED
+ IA2_EVENT_TEXT_CHANGED, // nsIAccessibleEvent::EVENT_TEXT_CHANGED
+ IA2_EVENT_TEXT_INSERTED, // nsIAccessibleEvent::EVENT_TEXT_INSERTED
+ IA2_EVENT_TEXT_REMOVED, // nsIAccessibleEvent::EVENT_TEXT_REMOVED
+ IA2_EVENT_TEXT_UPDATED, // nsIAccessibleEvent::EVENT_TEXT_UPDATED
+ IA2_EVENT_TEXT_SELECTION_CHANGED, // nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED
+ IA2_EVENT_VISIBLE_DATA_CHANGED, // nsIAccessibleEvent::EVENT_VISIBLE_DATA_CHANGED
+ IA2_EVENT_TEXT_COLUMN_CHANGED, // nsIAccessibleEvent::EVENT_TEXT_COLUMN_CHANGED
+ IA2_EVENT_SECTION_CHANGED, // nsIAccessibleEvent::EVENT_SECTION_CHANGED
+ IA2_EVENT_TABLE_CAPTION_CHANGED, // nsIAccessibleEvent::EVENT_TABLE_CAPTION_CHANGED
+ IA2_EVENT_TABLE_MODEL_CHANGED, // nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED
+ IA2_EVENT_TABLE_SUMMARY_CHANGED, // nsIAccessibleEvent::EVENT_TABLE_SUMMARY_CHANGED
+ IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED, // nsIAccessibleEvent::EVENT_TABLE_ROW_DESCRIPTION_CHANGED
+ IA2_EVENT_TABLE_ROW_HEADER_CHANGED, // nsIAccessibleEvent::EVENT_TABLE_ROW_HEADER_CHANGED
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_TABLE_ROW_DELETE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_TABLE_ROW_REORDER
+ IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED, // nsIAccessibleEvent::EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED
+ IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED, // nsIAccessibleEvent::EVENT_TABLE_COLUMN_HEADER_CHANGED
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_TABLE_COLUMN_INSERT
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_TABLE_COLUMN_DELETE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_TABLE_COLUMN_REORDER
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_WINDOW_CREATE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_WINDOW_DESTROY
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_WINDOW_RESIZE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_WINDOW_RESTORE
+ IA2_EVENT_HYPERLINK_END_INDEX_CHANGED, // nsIAccessibleEvent::EVENT_HYPERLINK_END_INDEX_CHANGED
+ IA2_EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED, // nsIAccessibleEvent::EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED
+ IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED, // nsIAccessibleEvent::EVENT_HYPERLINK_SELECTED_LINK_CHANGED
+ IA2_EVENT_HYPERTEXT_LINK_ACTIVATED, // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_ACTIVATED
+ IA2_EVENT_HYPERTEXT_LINK_SELECTED, // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_SELECTED
+ IA2_EVENT_HYPERLINK_START_INDEX_CHANGED, // nsIAccessibleEvent::EVENT_HYPERLINK_START_INDEX_CHANGED
+ IA2_EVENT_HYPERTEXT_CHANGED, // nsIAccessibleEvent::EVENT_HYPERTEXT_CHANGED
+ IA2_EVENT_HYPERTEXT_NLINKS_CHANGED, // nsIAccessibleEvent::EVENT_HYPERTEXT_NLINKS_CHANGED
+ IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED, // nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED
+ EVENT_OBJECT_VALUECHANGE // nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE
+};
+
diff --git a/accessible/windows/msaa/nsWinUtils.cpp b/accessible/windows/msaa/nsWinUtils.cpp
new file mode 100644
index 000000000..b49cd0263
--- /dev/null
+++ b/accessible/windows/msaa/nsWinUtils.cpp
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsWinUtils.h"
+
+#include "Compatibility.h"
+#include "DocAccessible.h"
+#include "nsAccessibilityService.h"
+#include "nsCoreUtils.h"
+
+#include "mozilla/Preferences.h"
+#include "nsArrayUtils.h"
+#include "nsIArray.h"
+#include "nsICSSDeclaration.h"
+#include "nsIDocument.h"
+#include "nsIDocShellTreeItem.h"
+#include "mozilla/dom/Element.h"
+#include "nsXULAppAPI.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+using mozilla::dom::Element;
+
+// Window property used by ipc related code in identifying accessible
+// tab windows.
+const wchar_t* kPropNameTabContent = L"AccessibleTabWindow";
+
+/**
+ * WindowProc to process WM_GETOBJECT messages, used in windows emulation mode.
+ */
+static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg,
+ WPARAM wParam, LPARAM lParam);
+
+bool nsWinUtils::sWindowEmulationStarted = false;
+
+already_AddRefed<nsIDOMCSSStyleDeclaration>
+nsWinUtils::GetComputedStyleDeclaration(nsIContent* aContent)
+{
+ nsIContent* elm = nsCoreUtils::GetDOMElementFor(aContent);
+ if (!elm)
+ return nullptr;
+
+ // Returns number of items in style declaration
+ nsCOMPtr<nsPIDOMWindowInner> window = elm->OwnerDoc()->GetInnerWindow();
+ if (!window)
+ return nullptr;
+
+ ErrorResult dummy;
+ nsCOMPtr<nsICSSDeclaration> cssDecl;
+ nsCOMPtr<Element> domElement(do_QueryInterface(elm));
+ cssDecl = window->GetComputedStyle(*domElement, EmptyString(), dummy);
+ nsCOMPtr<nsIDOMCSSStyleDeclaration> domDecl = do_QueryInterface(cssDecl);
+ dummy.SuppressException();
+ return domDecl.forget();
+}
+
+bool
+nsWinUtils::MaybeStartWindowEmulation()
+{
+ // Register window class that'll be used for document accessibles associated
+ // with tabs.
+ if (IPCAccessibilityActive())
+ return false;
+
+ if (Compatibility::IsJAWS() || Compatibility::IsWE() ||
+ Compatibility::IsDolphin() ||
+ XRE_IsContentProcess()) {
+ RegisterNativeWindow(kClassNameTabContent);
+ sWindowEmulationStarted = true;
+ return true;
+ }
+
+ return false;
+}
+
+void
+nsWinUtils::ShutdownWindowEmulation()
+{
+ // Unregister window call that's used for document accessibles associated
+ // with tabs.
+ if (IsWindowEmulationStarted()) {
+ ::UnregisterClassW(kClassNameTabContent, GetModuleHandle(nullptr));
+ sWindowEmulationStarted = false;
+ }
+}
+
+void
+nsWinUtils::RegisterNativeWindow(LPCWSTR aWindowClass)
+{
+ WNDCLASSW wc;
+ wc.style = CS_GLOBALCLASS;
+ wc.lpfnWndProc = WindowProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(nullptr);
+ wc.hIcon = nullptr;
+ wc.hCursor = nullptr;
+ wc.hbrBackground = nullptr;
+ wc.lpszMenuName = nullptr;
+ wc.lpszClassName = aWindowClass;
+ ::RegisterClassW(&wc);
+}
+
+HWND
+nsWinUtils::CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd,
+ int aX, int aY, int aWidth, int aHeight,
+ bool aIsActive)
+{
+ HWND hwnd = ::CreateWindowExW(WS_EX_TRANSPARENT, aWindowClass,
+ L"NetscapeDispatchWnd",
+ WS_CHILD | (aIsActive ? WS_VISIBLE : 0),
+ aX, aY, aWidth, aHeight,
+ aParentWnd,
+ nullptr,
+ GetModuleHandle(nullptr),
+ nullptr);
+ if (hwnd) {
+ // Mark this window so that ipc related code can identify it.
+ ::SetPropW(hwnd, kPropNameTabContent, (HANDLE)1);
+ }
+ return hwnd;
+}
+
+void
+nsWinUtils::ShowNativeWindow(HWND aWnd)
+{
+ ::ShowWindow(aWnd, SW_SHOW);
+}
+
+void
+nsWinUtils::HideNativeWindow(HWND aWnd)
+{
+ ::SetWindowPos(aWnd, nullptr, 0, 0, 0, 0,
+ SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
+ SWP_NOZORDER | SWP_NOACTIVATE);
+}
+
+LRESULT CALLBACK
+WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ // Note, this window's message handling should not invoke any call that
+ // may result in a cross-process ipc call. Doing so may violate RPC
+ // message semantics.
+
+ switch (msg) {
+ case WM_GETOBJECT:
+ {
+ // Do explicit casting to make it working on 64bit systems (see bug 649236
+ // for details).
+ int32_t objId = static_cast<DWORD>(lParam);
+ if (objId == OBJID_CLIENT) {
+ DocAccessible* document =
+ reinterpret_cast<DocAccessible*>(::GetPropW(hWnd, kPropNameDocAcc));
+ if (document) {
+ IAccessible* msaaAccessible = nullptr;
+ document->GetNativeInterface((void**)&msaaAccessible); // does an addref
+ if (msaaAccessible) {
+ LRESULT result = ::LresultFromObject(IID_IAccessible, wParam,
+ msaaAccessible); // does an addref
+ msaaAccessible->Release(); // release extra addref
+ return result;
+ }
+ }
+ }
+ return 0;
+ }
+ case WM_NCHITTEST:
+ {
+ LRESULT lRet = ::DefWindowProc(hWnd, msg, wParam, lParam);
+ if (HTCLIENT == lRet)
+ lRet = HTTRANSPARENT;
+ return lRet;
+ }
+ }
+
+ return ::DefWindowProcW(hWnd, msg, wParam, lParam);
+}
diff --git a/accessible/windows/msaa/nsWinUtils.h b/accessible/windows/msaa/nsWinUtils.h
new file mode 100644
index 000000000..55089e722
--- /dev/null
+++ b/accessible/windows/msaa/nsWinUtils.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsWinUtils_h_
+#define nsWinUtils_h_
+
+#include <windows.h>
+
+#include "nsIDOMCSSStyleDeclaration.h"
+#include "nsCOMPtr.h"
+
+class nsIContent;
+
+namespace mozilla {
+namespace a11y {
+
+class DocAccessible;
+
+const LPCWSTR kClassNameRoot = L"MozillaUIWindowClass";
+const LPCWSTR kClassNameTabContent = L"MozillaContentWindowClass";
+const LPCWSTR kPropNameDocAcc = L"MozDocAccessible";
+
+class nsWinUtils
+{
+public:
+ /**
+ * Return computed styles declaration for the given node.
+ *
+ * @note Please use it carefully since it can shutdown the accessible tree
+ * you operate on.
+ */
+ static already_AddRefed<nsIDOMCSSStyleDeclaration>
+ GetComputedStyleDeclaration(nsIContent* aContent);
+
+ /**
+ * Start window emulation if presence of specific AT is detected.
+ */
+ static bool MaybeStartWindowEmulation();
+
+ /**
+ * Free resources used for window emulation.
+ */
+ static void ShutdownWindowEmulation();
+
+ /**
+ * Return true if window emulation is started.
+ */
+ static bool IsWindowEmulationStarted() { return sWindowEmulationStarted; }
+
+ /**
+ * Helper to register window class.
+ */
+ static void RegisterNativeWindow(LPCWSTR aWindowClass);
+
+ /**
+ * Helper to create a window.
+ */
+ static HWND CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd,
+ int aX, int aY, int aWidth, int aHeight,
+ bool aIsActive);
+
+ /**
+ * Helper to show window.
+ */
+ static void ShowNativeWindow(HWND aWnd);
+
+ /**
+ * Helper to hide window.
+ */
+ static void HideNativeWindow(HWND aWnd);
+
+private:
+ /**
+ * Flag that indicates if window emulation is started.
+ */
+ static bool sWindowEmulationStarted;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/sdn/moz.build b/accessible/windows/sdn/moz.build
new file mode 100644
index 000000000..ae0d5e20d
--- /dev/null
+++ b/accessible/windows/sdn/moz.build
@@ -0,0 +1,24 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+ 'sdnAccessible.cpp',
+ 'sdnDocAccessible.cpp',
+ 'sdnTextAccessible.cpp',
+]
+
+LOCAL_INCLUDES += [
+ '/accessible/base',
+ '/accessible/generic',
+ '/accessible/html',
+ '/accessible/windows/msaa',
+ '/accessible/xpcom',
+ '/accessible/xul',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
diff --git a/accessible/windows/sdn/sdnAccessible-inl.h b/accessible/windows/sdn/sdnAccessible-inl.h
new file mode 100644
index 000000000..a3d1a95e8
--- /dev/null
+++ b/accessible/windows/sdn/sdnAccessible-inl.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_sdnAccessible_inl_h_
+#define mozilla_a11y_sdnAccessible_inl_h_
+
+#include "sdnAccessible.h"
+
+#include "DocAccessible.h"
+#include "nsAccessibilityService.h"
+
+namespace mozilla {
+namespace a11y {
+
+inline DocAccessible*
+sdnAccessible::GetDocument() const
+{
+ return GetExistingDocAccessible(mNode->OwnerDoc());
+}
+
+inline Accessible*
+sdnAccessible::GetAccessible() const
+{
+ DocAccessible* document = GetDocument();
+ return document ? document->GetAccessibleEvenIfNotInMap(mNode) : nullptr;
+}
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // mozilla_a11y_sdnAccessible_inl_h_
diff --git a/accessible/windows/sdn/sdnAccessible.cpp b/accessible/windows/sdn/sdnAccessible.cpp
new file mode 100644
index 000000000..909b0779c
--- /dev/null
+++ b/accessible/windows/sdn/sdnAccessible.cpp
@@ -0,0 +1,539 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdnAccessible-inl.h"
+#include "ISimpleDOMNode_i.c"
+
+#include "DocAccessibleWrap.h"
+
+#include "nsAttrName.h"
+#include "nsCoreUtils.h"
+#include "nsIAccessibleTypes.h"
+#include "nsIDOMHTMLElement.h"
+#include "nsIDOMCSSStyleDeclaration.h"
+#include "nsNameSpaceManager.h"
+#include "nsServiceManagerUtils.h"
+#include "nsWinUtils.h"
+#include "nsRange.h"
+
+#include "mozilla/dom/BorrowedAttrInfo.h"
+#include "mozilla/dom/Element.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+STDMETHODIMP
+sdnAccessible::QueryInterface(REFIID aREFIID, void** aInstancePtr)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aInstancePtr)
+ return E_FAIL;
+ *aInstancePtr = nullptr;
+
+ if (aREFIID == IID_ISimpleDOMNode) {
+ *aInstancePtr = static_cast<ISimpleDOMNode*>(this);
+ AddRef();
+ return S_OK;
+ }
+
+ AccessibleWrap* accessible = static_cast<AccessibleWrap*>(GetAccessible());
+ if (accessible)
+ return accessible->QueryInterface(aREFIID, aInstancePtr);
+
+ // IUnknown* is the canonical one if and only if this accessible doesn't have
+ // an accessible.
+ if (aREFIID == IID_IUnknown) {
+ *aInstancePtr = static_cast<ISimpleDOMNode*>(this);
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_nodeInfo(BSTR __RPC_FAR* aNodeName,
+ short __RPC_FAR* aNameSpaceID,
+ BSTR __RPC_FAR* aNodeValue,
+ unsigned int __RPC_FAR* aNumChildren,
+ unsigned int __RPC_FAR* aUniqueID,
+ unsigned short __RPC_FAR* aNodeType)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNodeName || !aNameSpaceID || !aNodeValue || !aNumChildren ||
+ !aUniqueID || !aNodeType)
+ return E_INVALIDARG;
+
+ *aNodeName = nullptr;
+ *aNameSpaceID = 0;
+ *aNodeValue = nullptr;
+ *aNumChildren = 0;
+ *aUniqueID = 0;
+ *aNodeType = 0;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mNode));
+
+ uint16_t nodeType = 0;
+ DOMNode->GetNodeType(&nodeType);
+ *aNodeType = static_cast<unsigned short>(nodeType);
+
+ if (*aNodeType != NODETYPE_TEXT) {
+ nsAutoString nodeName;
+ DOMNode->GetNodeName(nodeName);
+ *aNodeName = ::SysAllocString(nodeName.get());
+ }
+
+ nsAutoString nodeValue;
+ DOMNode->GetNodeValue(nodeValue);
+ *aNodeValue = ::SysAllocString(nodeValue.get());
+
+ *aNameSpaceID = mNode->IsNodeOfType(nsINode::eCONTENT) ?
+ static_cast<short>(mNode->AsContent()->GetNameSpaceID()) : 0;
+
+ // This is a unique ID for every content node. The 3rd party accessibility
+ // application can compare this to the childID we return for events such as
+ // focus events, to correlate back to data nodes in their internal object
+ // model.
+ Accessible* accessible = GetAccessible();
+ if (accessible) {
+ *aUniqueID = AccessibleWrap::GetChildIDFor(accessible);
+ } else {
+ *aUniqueID = - NS_PTR_TO_INT32(static_cast<void*>(this));
+ }
+
+ *aNumChildren = mNode->GetChildCount();
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_attributes(unsigned short aMaxAttribs,
+ BSTR __RPC_FAR* aAttribNames,
+ short __RPC_FAR* aNameSpaceIDs,
+ BSTR __RPC_FAR* aAttribValues,
+ unsigned short __RPC_FAR* aNumAttribs)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAttribNames || !aNameSpaceIDs || !aAttribValues || !aNumAttribs)
+ return E_INVALIDARG;
+
+ *aNumAttribs = 0;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!mNode->IsElement())
+ return S_FALSE;
+
+ dom::Element* elm = mNode->AsElement();
+ uint32_t numAttribs = elm->GetAttrCount();
+ if (numAttribs > aMaxAttribs)
+ numAttribs = aMaxAttribs;
+
+ *aNumAttribs = static_cast<unsigned short>(numAttribs);
+
+ for (uint32_t index = 0; index < numAttribs; index++) {
+ aNameSpaceIDs[index] = 0;
+ aAttribValues[index] = aAttribNames[index] = nullptr;
+ nsAutoString attributeValue;
+
+ dom::BorrowedAttrInfo attr = elm->GetAttrInfoAt(index);
+ attr.mValue->ToString(attributeValue);
+
+ aNameSpaceIDs[index] = static_cast<short>(attr.mName->NamespaceID());
+ aAttribNames[index] = ::SysAllocString(attr.mName->LocalName()->GetUTF16String());
+ aAttribValues[index] = ::SysAllocString(attributeValue.get());
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_attributesForNames(unsigned short aMaxAttribs,
+ BSTR __RPC_FAR* aAttribNames,
+ short __RPC_FAR* aNameSpaceID,
+ BSTR __RPC_FAR* aAttribValues)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAttribNames || !aNameSpaceID || !aAttribValues)
+ return E_INVALIDARG;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!mNode->IsElement())
+ return S_FALSE;
+
+ nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(mNode));
+ nsNameSpaceManager* nameSpaceManager = nsNameSpaceManager::GetInstance();
+
+ int32_t index = 0;
+ for (index = 0; index < aMaxAttribs; index++) {
+ aAttribValues[index] = nullptr;
+ if (aAttribNames[index]) {
+ nsAutoString attributeValue, nameSpaceURI;
+ nsAutoString attributeName(nsDependentString(
+ static_cast<const wchar_t*>(aAttribNames[index])));
+
+ nsresult rv = NS_OK;
+ if (aNameSpaceID[index]>0 &&
+ NS_SUCCEEDED(nameSpaceManager->GetNameSpaceURI(aNameSpaceID[index],
+ nameSpaceURI))) {
+ rv = domElement->GetAttributeNS(nameSpaceURI, attributeName,
+ attributeValue);
+ } else {
+ rv = domElement->GetAttribute(attributeName, attributeValue);
+ }
+
+ if (NS_SUCCEEDED(rv))
+ aAttribValues[index] = ::SysAllocString(attributeValue.get());
+ }
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_computedStyle(unsigned short aMaxStyleProperties,
+ boolean aUseAlternateView,
+ BSTR __RPC_FAR* aStyleProperties,
+ BSTR __RPC_FAR* aStyleValues,
+ unsigned short __RPC_FAR* aNumStyleProperties)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aStyleProperties || aStyleValues || !aNumStyleProperties)
+ return E_INVALIDARG;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ *aNumStyleProperties = 0;
+
+ if (mNode->IsNodeOfType(nsINode::eDOCUMENT))
+ return S_FALSE;
+
+ nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl =
+ nsWinUtils::GetComputedStyleDeclaration(mNode->AsContent());
+ NS_ENSURE_TRUE(cssDecl, E_FAIL);
+
+ uint32_t length = 0;
+ cssDecl->GetLength(&length);
+
+ uint32_t index = 0, realIndex = 0;
+ for (index = realIndex = 0; index < length && realIndex < aMaxStyleProperties;
+ index ++) {
+ nsAutoString property, value;
+
+ // Ignore -moz-* properties.
+ if (NS_SUCCEEDED(cssDecl->Item(index, property)) && property.CharAt(0) != '-')
+ cssDecl->GetPropertyValue(property, value); // Get property value
+
+ if (!value.IsEmpty()) {
+ aStyleProperties[realIndex] = ::SysAllocString(property.get());
+ aStyleValues[realIndex] = ::SysAllocString(value.get());
+ ++realIndex;
+ }
+ }
+
+ *aNumStyleProperties = static_cast<unsigned short>(realIndex);
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_computedStyleForProperties(unsigned short aNumStyleProperties,
+ boolean aUseAlternateView,
+ BSTR __RPC_FAR* aStyleProperties,
+ BSTR __RPC_FAR* aStyleValues)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aStyleProperties || !aStyleValues)
+ return E_INVALIDARG;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (mNode->IsNodeOfType(nsINode::eDOCUMENT))
+ return S_FALSE;
+
+ nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl =
+ nsWinUtils::GetComputedStyleDeclaration(mNode->AsContent());
+ NS_ENSURE_TRUE(cssDecl, E_FAIL);
+
+ uint32_t index = 0;
+ for (index = 0; index < aNumStyleProperties; index++) {
+ nsAutoString value;
+ if (aStyleProperties[index])
+ cssDecl->GetPropertyValue(nsDependentString(aStyleProperties[index]), value); // Get property value
+ aStyleValues[index] = ::SysAllocString(value.get());
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::scrollTo(boolean aScrollTopLeft)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ DocAccessible* document = GetDocument();
+ if (!document) // that's IsDefunct check
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!mNode->IsContent())
+ return S_FALSE;
+
+ uint32_t scrollType =
+ aScrollTopLeft ? nsIAccessibleScrollType::SCROLL_TYPE_TOP_LEFT :
+ nsIAccessibleScrollType::SCROLL_TYPE_BOTTOM_RIGHT;
+
+ nsCoreUtils::ScrollTo(document->PresShell(), mNode->AsContent(), scrollType);
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_parentNode(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNode)
+ return E_INVALIDARG;
+ *aNode = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsINode* resultNode = mNode->GetParentNode();
+ if (resultNode) {
+ *aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
+ (*aNode)->AddRef();
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_firstChild(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNode)
+ return E_INVALIDARG;
+ *aNode = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsINode* resultNode = mNode->GetFirstChild();
+ if (resultNode) {
+ *aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
+ (*aNode)->AddRef();
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_lastChild(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNode)
+ return E_INVALIDARG;
+ *aNode = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsINode* resultNode = mNode->GetLastChild();
+ if (resultNode) {
+ *aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
+ (*aNode)->AddRef();
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_previousSibling(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNode)
+ return E_INVALIDARG;
+ *aNode = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsINode* resultNode = mNode->GetPreviousSibling();
+ if (resultNode) {
+ *aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
+ (*aNode)->AddRef();
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_nextSibling(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNode)
+ return E_INVALIDARG;
+ *aNode = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsINode* resultNode = mNode->GetNextSibling();
+ if (resultNode) {
+ *aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
+ (*aNode)->AddRef();
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_childAt(unsigned aChildIndex,
+ ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNode)
+ return E_INVALIDARG;
+ *aNode = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsINode* resultNode = mNode->GetChildAt(aChildIndex);
+ if (resultNode) {
+ *aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
+ (*aNode)->AddRef();
+ }
+
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_innerHTML(BSTR __RPC_FAR* aInnerHTML)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aInnerHTML)
+ return E_INVALIDARG;
+ *aInnerHTML = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (!mNode->IsElement())
+ return S_FALSE;
+
+ nsAutoString innerHTML;
+ mNode->AsElement()->GetInnerHTML(innerHTML);
+ if (innerHTML.IsEmpty())
+ return S_FALSE;
+
+ *aInnerHTML = ::SysAllocStringLen(innerHTML.get(), innerHTML.Length());
+ if (!*aInnerHTML)
+ return E_OUTOFMEMORY;
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_localInterface(void __RPC_FAR *__RPC_FAR* aLocalInterface)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aLocalInterface)
+ return E_INVALIDARG;
+ *aLocalInterface = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ *aLocalInterface = this;
+ AddRef();
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnAccessible::get_language(BSTR __RPC_FAR* aLanguage)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aLanguage)
+ return E_INVALIDARG;
+ *aLanguage = nullptr;
+
+ if (IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString language;
+ if (mNode->IsContent())
+ nsCoreUtils::GetLanguageFor(mNode->AsContent(), nullptr, language);
+ if (language.IsEmpty()) { // Nothing found, so use document's language
+ mNode->OwnerDoc()->GetHeaderData(nsGkAtoms::headerContentLanguage,
+ language);
+ }
+
+ if (language.IsEmpty())
+ return S_FALSE;
+
+ *aLanguage = ::SysAllocStringLen(language.get(), language.Length());
+ if (!*aLanguage)
+ return E_OUTOFMEMORY;
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
diff --git a/accessible/windows/sdn/sdnAccessible.h b/accessible/windows/sdn/sdnAccessible.h
new file mode 100644
index 000000000..2876ad270
--- /dev/null
+++ b/accessible/windows/sdn/sdnAccessible.h
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_sdnAccessible_h_
+#define mozilla_a11y_sdnAccessible_h_
+
+#include "ISimpleDOMNode.h"
+#include "AccessibleWrap.h"
+#include "IUnknownImpl.h"
+
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+namespace a11y {
+
+class sdnAccessible final : public ISimpleDOMNode
+{
+public:
+ sdnAccessible(nsINode* aNode) :
+ mNode(aNode)
+ {
+ if (!mNode)
+ MOZ_CRASH();
+ }
+ ~sdnAccessible() { }
+
+ /**
+ * Retrun if the object is defunct.
+ */
+ bool IsDefunct() const { return !GetDocument(); }
+
+ /**
+ * Return a document accessible it belongs to if any.
+ */
+ DocAccessible* GetDocument() const;
+
+ /*
+ * Return associated accessible if any.
+ */
+ Accessible* GetAccessible() const;
+
+ //IUnknown
+ DECL_IUNKNOWN
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_nodeInfo(
+ /* [out] */ BSTR __RPC_FAR* aNodeName,
+ /* [out] */ short __RPC_FAR* aNameSpaceID,
+ /* [out] */ BSTR __RPC_FAR* aNodeValue,
+ /* [out] */ unsigned int __RPC_FAR* aNumChildren,
+ /* [out] */ unsigned int __RPC_FAR* aUniqueID,
+ /* [out][retval] */ unsigned short __RPC_FAR* aNodeType);
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_attributes(
+ /* [in] */ unsigned short aMaxAttribs,
+ /* [length_is][size_is][out] */ BSTR __RPC_FAR* aAttribNames,
+ /* [length_is][size_is][out] */ short __RPC_FAR* aNameSpaceIDs,
+ /* [length_is][size_is][out] */ BSTR __RPC_FAR* aAttribValues,
+ /* [out][retval] */ unsigned short __RPC_FAR* aNumAttribs);
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_attributesForNames(
+ /* [in] */ unsigned short aMaxAttribs,
+ /* [length_is][size_is][in] */ BSTR __RPC_FAR* aAttribNames,
+ /* [length_is][size_is][in] */ short __RPC_FAR* aNameSpaceID,
+ /* [length_is][size_is][retval] */ BSTR __RPC_FAR* aAttribValues);
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_computedStyle(
+ /* [in] */ unsigned short aMaxStyleProperties,
+ /* [in] */ boolean aUseAlternateView,
+ /* [length_is][size_is][out] */ BSTR __RPC_FAR* aStyleProperties,
+ /* [length_is][size_is][out] */ BSTR __RPC_FAR* aStyleValues,
+ /* [out][retval] */ unsigned short __RPC_FAR* aNumStyleProperties);
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_computedStyleForProperties(
+ /* [in] */ unsigned short aNumStyleProperties,
+ /* [in] */ boolean aUseAlternateView,
+ /* [length_is][size_is][in] */ BSTR __RPC_FAR* aStyleProperties,
+ /* [length_is][size_is][out][retval] */ BSTR __RPC_FAR* aStyleValues);
+
+ virtual HRESULT STDMETHODCALLTYPE scrollTo(/* [in] */ boolean aScrollTopLeft);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_parentNode(
+ /* [out][retval] */ ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_firstChild(
+ /* [out][retval] */ ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_lastChild(
+ /* [out][retval] */ ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_previousSibling(
+ /* [out][retval] */ ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nextSibling(
+ /* [out][retval] */ ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_childAt(
+ /* [in] */ unsigned aChildIndex,
+ /* [out][retval] */ ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_innerHTML(
+ /* [out][retval] */ BSTR __RPC_FAR* aInnerHTML);
+
+ virtual /* [local][propget] */ HRESULT STDMETHODCALLTYPE get_localInterface(
+ /* [retval][out] */ void __RPC_FAR *__RPC_FAR* aLocalInterface);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_language(
+ /* [out][retval] */ BSTR __RPC_FAR* aLanguage);
+
+private:
+ nsCOMPtr<nsINode> mNode;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // mozilla_a11y_sdnAccessible_h_
diff --git a/accessible/windows/sdn/sdnDocAccessible.cpp b/accessible/windows/sdn/sdnDocAccessible.cpp
new file mode 100644
index 000000000..07b39e66f
--- /dev/null
+++ b/accessible/windows/sdn/sdnDocAccessible.cpp
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdnDocAccessible.h"
+
+#include "ISimpleDOMDocument_i.c"
+
+#include "nsNameSpaceManager.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// sdnDocAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+IMPL_IUNKNOWN_QUERY_HEAD(sdnDocAccessible)
+ IMPL_IUNKNOWN_QUERY_IFACE(ISimpleDOMDocument)
+IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mAccessible)
+
+STDMETHODIMP
+sdnDocAccessible::get_URL(BSTR __RPC_FAR* aURL)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aURL)
+ return E_INVALIDARG;
+ *aURL = nullptr;
+
+ if (mAccessible->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString URL;
+ mAccessible->URL(URL);
+ if (URL.IsEmpty())
+ return S_FALSE;
+
+ *aURL = ::SysAllocStringLen(URL.get(), URL.Length());
+ return *aURL ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnDocAccessible::get_title(BSTR __RPC_FAR* aTitle)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aTitle)
+ return E_INVALIDARG;
+ *aTitle = nullptr;
+
+ if (mAccessible->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString title;
+ mAccessible->Title(title);
+ *aTitle = ::SysAllocStringLen(title.get(), title.Length());
+ return *aTitle ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnDocAccessible::get_mimeType(BSTR __RPC_FAR* aMimeType)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aMimeType)
+ return E_INVALIDARG;
+ *aMimeType = nullptr;
+
+ if (mAccessible->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString mimeType;
+ mAccessible->MimeType(mimeType);
+ if (mimeType.IsEmpty())
+ return S_FALSE;
+
+ *aMimeType = ::SysAllocStringLen(mimeType.get(), mimeType.Length());
+ return *aMimeType ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnDocAccessible::get_docType(BSTR __RPC_FAR* aDocType)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aDocType)
+ return E_INVALIDARG;
+ *aDocType = nullptr;
+
+ if (mAccessible->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString docType;
+ mAccessible->DocType(docType);
+ if (docType.IsEmpty())
+ return S_FALSE;
+
+ *aDocType = ::SysAllocStringLen(docType.get(), docType.Length());
+ return *aDocType ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnDocAccessible::get_nameSpaceURIForID(short aNameSpaceID,
+ BSTR __RPC_FAR* aNameSpaceURI)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aNameSpaceURI)
+ return E_INVALIDARG;
+ *aNameSpaceURI = nullptr;
+
+ if (mAccessible->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ if (aNameSpaceID < 0)
+ return E_INVALIDARG; // -1 is kNameSpaceID_Unknown
+
+ nsAutoString nameSpaceURI;
+ nsNameSpaceManager* nameSpaceManager = nsNameSpaceManager::GetInstance();
+ if (nameSpaceManager)
+ nameSpaceManager->GetNameSpaceURI(aNameSpaceID, nameSpaceURI);
+
+ if (nameSpaceURI.IsEmpty())
+ return S_FALSE;
+
+ *aNameSpaceURI = ::SysAllocStringLen(nameSpaceURI.get(),
+ nameSpaceURI.Length());
+
+ return *aNameSpaceURI ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnDocAccessible::put_alternateViewMediaTypes(BSTR __RPC_FAR* aCommaSeparatedMediaTypes)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aCommaSeparatedMediaTypes)
+ return E_INVALIDARG;
+ *aCommaSeparatedMediaTypes = nullptr;
+
+ return mAccessible->IsDefunct() ? CO_E_OBJNOTCONNECTED : E_NOTIMPL;
+
+ A11Y_TRYBLOCK_END
+}
diff --git a/accessible/windows/sdn/sdnDocAccessible.h b/accessible/windows/sdn/sdnDocAccessible.h
new file mode 100644
index 000000000..22c7124b2
--- /dev/null
+++ b/accessible/windows/sdn/sdnDocAccessible.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_sdnDocAccessible_h_
+#define mozilla_a11y_sdnDocAccessible_h_
+
+#include "ISimpleDOMDocument.h"
+#include "IUnknownImpl.h"
+
+#include "DocAccessibleWrap.h"
+
+namespace mozilla {
+namespace a11y {
+
+class sdnDocAccessible final : public ISimpleDOMDocument
+{
+public:
+ sdnDocAccessible(DocAccessibleWrap* aAccessible) : mAccessible(aAccessible) {};
+ ~sdnDocAccessible() { };
+
+ DECL_IUNKNOWN
+
+ // ISimpleDOMDocument
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_URL(
+ /* [out] */ BSTR __RPC_FAR *url);
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_title(
+ /* [out] */ BSTR __RPC_FAR *title);
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_mimeType(
+ /* [out] */ BSTR __RPC_FAR *mimeType);
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_docType(
+ /* [out] */ BSTR __RPC_FAR *docType);
+
+ virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_nameSpaceURIForID(
+ /* [in] */ short nameSpaceID,
+ /* [out] */ BSTR __RPC_FAR *nameSpaceURI);
+
+ virtual /* [id] */ HRESULT STDMETHODCALLTYPE put_alternateViewMediaTypes(
+ /* [in] */ BSTR __RPC_FAR *commaSeparatedMediaTypes);
+
+protected:
+ RefPtr<DocAccessibleWrap> mAccessible;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/sdn/sdnTextAccessible.cpp b/accessible/windows/sdn/sdnTextAccessible.cpp
new file mode 100644
index 000000000..b51caf44e
--- /dev/null
+++ b/accessible/windows/sdn/sdnTextAccessible.cpp
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdnTextAccessible.h"
+
+#include "ISimpleDOMText_i.c"
+
+#include "nsCoreUtils.h"
+#include "DocAccessible.h"
+
+#include "nsIFrame.h"
+#include "nsFontMetrics.h"
+#include "nsPresContext.h"
+#include "nsLayoutUtils.h"
+#include "nsRange.h"
+#include "gfxFont.h"
+#include "nsIAccessibleTypes.h"
+#include "mozilla/gfx/2D.h"
+
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// sdnTextAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+IMPL_IUNKNOWN_QUERY_HEAD(sdnTextAccessible)
+ IMPL_IUNKNOWN_QUERY_IFACE(ISimpleDOMText)
+IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mAccessible)
+
+STDMETHODIMP
+sdnTextAccessible::get_domText(BSTR __RPC_FAR* aText)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aText)
+ return E_INVALIDARG;
+ *aText = nullptr;
+
+ if (mAccessible->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString nodeValue;
+
+ nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mAccessible->GetContent()));
+ DOMNode->GetNodeValue(nodeValue);
+ if (nodeValue.IsEmpty())
+ return S_FALSE;
+
+ *aText = ::SysAllocStringLen(nodeValue.get(), nodeValue.Length());
+ return *aText ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnTextAccessible::get_clippedSubstringBounds(unsigned int aStartIndex,
+ unsigned int aEndIndex,
+ int __RPC_FAR* aX,
+ int __RPC_FAR* aY,
+ int __RPC_FAR* aWidth,
+ int __RPC_FAR* aHeight)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ nscoord x = 0, y = 0, width = 0, height = 0;
+ HRESULT rv = get_unclippedSubstringBounds(aStartIndex, aEndIndex,
+ &x, &y, &width, &height);
+ if (FAILED(rv))
+ return rv;
+
+ DocAccessible* document = mAccessible->Document();
+ NS_ASSERTION(document,
+ "There must always be a doc accessible, but there isn't. Crash!");
+
+ nsIntRect docRect = document->Bounds();
+ nsIntRect unclippedRect(x, y, width, height);
+
+ nsIntRect clippedRect;
+ clippedRect.IntersectRect(unclippedRect, docRect);
+
+ *aX = clippedRect.x;
+ *aY = clippedRect.y;
+ *aWidth = clippedRect.width;
+ *aHeight = clippedRect.height;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnTextAccessible::get_unclippedSubstringBounds(unsigned int aStartIndex,
+ unsigned int aEndIndex,
+ int __RPC_FAR* aX,
+ int __RPC_FAR* aY,
+ int __RPC_FAR* aWidth,
+ int __RPC_FAR* aHeight)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aX || !aY || !aWidth || !aHeight)
+ return E_INVALIDARG;
+ *aX = *aY = *aWidth = *aHeight = 0;
+
+ if (mAccessible->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsIFrame *frame = mAccessible->GetFrame();
+ NS_ENSURE_TRUE(frame, E_FAIL);
+
+ nsPoint startPoint, endPoint;
+ nsIFrame* startFrame = GetPointFromOffset(frame, aStartIndex, true, startPoint);
+ nsIFrame* endFrame = GetPointFromOffset(frame, aEndIndex, false, endPoint);
+ if (!startFrame || !endFrame)
+ return E_FAIL;
+
+ nsRect sum;
+ nsIFrame* iter = startFrame;
+ nsIFrame* stopLoopFrame = endFrame->GetNextContinuation();
+ for (; iter != stopLoopFrame; iter = iter->GetNextContinuation()) {
+ nsRect rect = iter->GetScreenRectInAppUnits();
+ nscoord start = (iter == startFrame) ? startPoint.x : 0;
+ nscoord end = (iter == endFrame) ? endPoint.x : rect.width;
+ rect.x += start;
+ rect.width = end - start;
+ sum.UnionRect(sum, rect);
+ }
+
+ nsPresContext* presContext = mAccessible->Document()->PresContext();
+ *aX = presContext->AppUnitsToDevPixels(sum.x);
+ *aY = presContext->AppUnitsToDevPixels(sum.y);
+ *aWidth = presContext->AppUnitsToDevPixels(sum.width);
+ *aHeight = presContext->AppUnitsToDevPixels(sum.height);
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnTextAccessible::scrollToSubstring(unsigned int aStartIndex,
+ unsigned int aEndIndex)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (mAccessible->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ RefPtr<nsRange> range = new nsRange(mAccessible->GetContent());
+ if (NS_FAILED(range->SetStart(mAccessible->GetContent(), aStartIndex)))
+ return E_FAIL;
+
+ if (NS_FAILED(range->SetEnd(mAccessible->GetContent(), aEndIndex)))
+ return E_FAIL;
+
+ nsresult rv =
+ nsCoreUtils::ScrollSubstringTo(mAccessible->GetFrame(), range,
+ nsIAccessibleScrollType::SCROLL_TYPE_ANYWHERE);
+ return GetHRESULT(rv);
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+sdnTextAccessible::get_fontFamily(BSTR __RPC_FAR* aFontFamily)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aFontFamily)
+ return E_INVALIDARG;
+ *aFontFamily = nullptr;
+
+ if (mAccessible->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ nsIFrame* frame = mAccessible->GetFrame();
+ if (!frame)
+ return E_FAIL;
+
+ RefPtr<nsFontMetrics> fm =
+ nsLayoutUtils::GetFontMetricsForFrame(frame, 1.0f);
+
+ const nsString& name =
+ fm->GetThebesFontGroup()->GetFirstValidFont()->GetName();
+ if (name.IsEmpty())
+ return S_FALSE;
+
+ *aFontFamily = ::SysAllocStringLen(name.get(), name.Length());
+ return *aFontFamily ? S_OK : E_OUTOFMEMORY;
+
+ A11Y_TRYBLOCK_END
+}
+
+nsIFrame*
+sdnTextAccessible::GetPointFromOffset(nsIFrame* aContainingFrame,
+ int32_t aOffset,
+ bool aPreferNext,
+ nsPoint& aOutPoint)
+{
+ nsIFrame* textFrame = nullptr;
+ int32_t outOffset;
+ aContainingFrame->GetChildFrameContainingOffset(aOffset, aPreferNext,
+ &outOffset, &textFrame);
+ if (textFrame)
+ textFrame->GetPointFromOffset(aOffset, &aOutPoint);
+
+ return textFrame;
+}
diff --git a/accessible/windows/sdn/sdnTextAccessible.h b/accessible/windows/sdn/sdnTextAccessible.h
new file mode 100644
index 000000000..ed8eecf29
--- /dev/null
+++ b/accessible/windows/sdn/sdnTextAccessible.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_sdnTextAccessible_h_
+#define mozilla_a11y_sdnTextAccessible_h_
+
+#include "ISimpleDOMText.h"
+#include "IUnknownImpl.h"
+
+#include "AccessibleWrap.h"
+
+class nsIFrame;
+struct nsPoint;
+
+namespace mozilla {
+namespace a11y {
+
+class sdnTextAccessible final : public ISimpleDOMText
+{
+public:
+ sdnTextAccessible(AccessibleWrap* aAccessible) : mAccessible(aAccessible) {};
+ ~sdnTextAccessible() {}
+
+ DECL_IUNKNOWN
+
+ // ISimpleDOMText
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_domText(
+ /* [retval][out] */ BSTR __RPC_FAR *aText);
+
+ virtual HRESULT STDMETHODCALLTYPE get_clippedSubstringBounds(
+ /* [in] */ unsigned int startIndex,
+ /* [in] */ unsigned int endIndex,
+ /* [out] */ int __RPC_FAR* aX,
+ /* [out] */ int __RPC_FAR* aY,
+ /* [out] */ int __RPC_FAR* aWidth,
+ /* [out] */ int __RPC_FAR* aHeight);
+
+ virtual HRESULT STDMETHODCALLTYPE get_unclippedSubstringBounds(
+ /* [in] */ unsigned int aStartIndex,
+ /* [in] */ unsigned int aEndIndex,
+ /* [out] */ int __RPC_FAR* aX,
+ /* [out] */ int __RPC_FAR* aY,
+ /* [out] */ int __RPC_FAR* aWidth,
+ /* [out] */ int __RPC_FAR* aHeight);
+
+ virtual HRESULT STDMETHODCALLTYPE scrollToSubstring(
+ /* [in] */ unsigned int aStartIndex,
+ /* [in] */ unsigned int aEndIndex);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_fontFamily(
+ /* [retval][out] */ BSTR __RPC_FAR* aFontFamily);
+
+private:
+ /**
+ * Return child frame containing offset on success.
+ */
+ nsIFrame* GetPointFromOffset(nsIFrame* aContainingFrame,
+ int32_t aOffset, bool aPreferNext,
+ nsPoint& aOutPoint);
+
+ RefPtr<AccessibleWrap> mAccessible;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/uia/moz.build b/accessible/windows/uia/moz.build
new file mode 100644
index 000000000..afc150e11
--- /dev/null
+++ b/accessible/windows/uia/moz.build
@@ -0,0 +1,22 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SOURCES += [
+ 'uiaRawElmProvider.cpp',
+]
+
+LOCAL_INCLUDES += [
+ '/accessible/base',
+ '/accessible/generic',
+ '/accessible/html',
+ '/accessible/windows/msaa',
+ '/accessible/xpcom',
+ '/accessible/xul',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
diff --git a/accessible/windows/uia/uiaRawElmProvider.cpp b/accessible/windows/uia/uiaRawElmProvider.cpp
new file mode 100644
index 000000000..54e54766d
--- /dev/null
+++ b/accessible/windows/uia/uiaRawElmProvider.cpp
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "uiaRawElmProvider.h"
+
+#include "AccessibleWrap.h"
+#include "ARIAMap.h"
+#include "nsIPersistentProperties2.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// uiaRawElmProvider
+////////////////////////////////////////////////////////////////////////////////
+
+IMPL_IUNKNOWN2(uiaRawElmProvider,
+ IAccessibleEx,
+ IRawElementProviderSimple)
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessibleEx
+
+STDMETHODIMP
+uiaRawElmProvider::GetObjectForChild(long aIdChild,
+ __RPC__deref_out_opt IAccessibleEx** aAccEx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAccEx)
+ return E_INVALIDARG;
+
+ *aAccEx = nullptr;
+
+ return mAcc->IsDefunct() ? CO_E_OBJNOTCONNECTED : S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+uiaRawElmProvider::GetIAccessiblePair(__RPC__deref_out_opt IAccessible** aAcc,
+ __RPC__out long* aIdChild)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aAcc || !aIdChild)
+ return E_INVALIDARG;
+
+ *aAcc = nullptr;
+ *aIdChild = 0;
+
+ if (mAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ *aIdChild = CHILDID_SELF;
+ *aAcc = mAcc;
+ mAcc->AddRef();
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+uiaRawElmProvider::GetRuntimeId(__RPC__deref_out_opt SAFEARRAY** aRuntimeIds)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRuntimeIds)
+ return E_INVALIDARG;
+
+ int ids[] = { UiaAppendRuntimeId, static_cast<int>(reinterpret_cast<intptr_t>(mAcc->UniqueID())) };
+ *aRuntimeIds = SafeArrayCreateVector(VT_I4, 0, 2);
+ if (!*aRuntimeIds)
+ return E_OUTOFMEMORY;
+
+ for (LONG i = 0; i < (LONG)ArrayLength(ids); i++)
+ SafeArrayPutElement(*aRuntimeIds, &i, (void*)&(ids[i]));
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+uiaRawElmProvider::ConvertReturnedElement(__RPC__in_opt IRawElementProviderSimple* aRawElmProvider,
+ __RPC__deref_out_opt IAccessibleEx** aAccEx)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRawElmProvider || !aAccEx)
+ return E_INVALIDARG;
+
+ *aAccEx = nullptr;
+
+ void* instancePtr = nullptr;
+ HRESULT hr = aRawElmProvider->QueryInterface(IID_IAccessibleEx, &instancePtr);
+ if (SUCCEEDED(hr))
+ *aAccEx = static_cast<IAccessibleEx*>(instancePtr);
+
+ return hr;
+
+ A11Y_TRYBLOCK_END
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IRawElementProviderSimple
+
+STDMETHODIMP
+uiaRawElmProvider::get_ProviderOptions(__RPC__out enum ProviderOptions* aOptions)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aOptions)
+ return E_INVALIDARG;
+
+ // This method is not used with IAccessibleEx implementations.
+ *aOptions = ProviderOptions_ServerSideProvider;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+uiaRawElmProvider::GetPatternProvider(PATTERNID aPatternId,
+ __RPC__deref_out_opt IUnknown** aPatternProvider)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aPatternProvider)
+ return E_INVALIDARG;
+
+ *aPatternProvider = nullptr;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId,
+ __RPC__out VARIANT* aPropertyValue)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aPropertyValue)
+ return E_INVALIDARG;
+
+ if (mAcc->IsDefunct())
+ return CO_E_OBJNOTCONNECTED;
+
+ aPropertyValue->vt = VT_EMPTY;
+
+ switch (aPropertyId) {
+ // Accelerator Key / shortcut.
+ case UIA_AcceleratorKeyPropertyId: {
+ nsAutoString keyString;
+
+ mAcc->KeyboardShortcut().ToString(keyString);
+
+ if (!keyString.IsEmpty()) {
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(keyString.get());
+ return S_OK;
+ }
+
+ break;
+ }
+
+ // Access Key / mneumonic.
+ case UIA_AccessKeyPropertyId: {
+ nsAutoString keyString;
+
+ mAcc->AccessKey().ToString(keyString);
+
+ if (!keyString.IsEmpty()) {
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(keyString.get());
+ return S_OK;
+ }
+
+ break;
+ }
+
+ //ARIA Role / shortcut
+ case UIA_AriaRolePropertyId: {
+ nsAutoString xmlRoles;
+
+ nsCOMPtr<nsIPersistentProperties> attributes = mAcc->Attributes();
+ attributes->GetStringProperty(NS_LITERAL_CSTRING("xml-roles"), xmlRoles);
+
+ if(!xmlRoles.IsEmpty()) {
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(xmlRoles.get());
+ return S_OK;
+ }
+
+ break;
+ }
+
+ //ARIA Properties
+ case UIA_AriaPropertiesPropertyId: {
+ nsAutoString ariaProperties;
+
+ aria::AttrIterator attribIter(mAcc->GetContent());
+ nsAutoString attribName, attribValue;
+ while (attribIter.Next(attribName, attribValue)) {
+ ariaProperties.Append(attribName);
+ ariaProperties.Append('=');
+ ariaProperties.Append(attribValue);
+ ariaProperties.Append(';');
+ }
+
+ if (!ariaProperties.IsEmpty()) {
+ //remove last delimiter:
+ ariaProperties.Truncate(ariaProperties.Length()-1);
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(ariaProperties.get());
+ return S_OK;
+ }
+
+ break;
+ }
+ }
+
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_HostRawElementProvider(__RPC__deref_out_opt IRawElementProviderSimple** aRawElmProvider)
+{
+ A11Y_TRYBLOCK_BEGIN
+
+ if (!aRawElmProvider)
+ return E_INVALIDARG;
+
+ // This method is not used with IAccessibleEx implementations.
+ *aRawElmProvider = nullptr;
+ return S_OK;
+
+ A11Y_TRYBLOCK_END
+}
diff --git a/accessible/windows/uia/uiaRawElmProvider.h b/accessible/windows/uia/uiaRawElmProvider.h
new file mode 100644
index 000000000..f32daa19b
--- /dev/null
+++ b/accessible/windows/uia/uiaRawElmProvider.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_uiaRawElmProvider_h__
+#define mozilla_a11y_uiaRawElmProvider_h__
+
+#include "objbase.h"
+#include "AccessibleWrap.h"
+#include "IUnknownImpl.h"
+#include "uiautomation.h"
+
+namespace mozilla {
+namespace a11y {
+
+class AccessibleWrap;
+
+/**
+ * IRawElementProviderSimple implementation (maintains IAccessibleEx approach).
+ */
+class uiaRawElmProvider final : public IAccessibleEx,
+ public IRawElementProviderSimple
+{
+public:
+ uiaRawElmProvider(AccessibleWrap* aAcc) : mAcc(aAcc) { }
+
+ // IUnknown
+ DECL_IUNKNOWN
+
+ // IAccessibleEx
+ virtual HRESULT STDMETHODCALLTYPE GetObjectForChild(
+ /* [in] */ long aIdChild,
+ /* [retval][out] */ __RPC__deref_out_opt IAccessibleEx** aAccEx);
+
+ virtual HRESULT STDMETHODCALLTYPE GetIAccessiblePair(
+ /* [out] */ __RPC__deref_out_opt IAccessible** aAcc,
+ /* [out] */ __RPC__out long* aIdChild);
+
+ virtual HRESULT STDMETHODCALLTYPE GetRuntimeId(
+ /* [retval][out] */ __RPC__deref_out_opt SAFEARRAY** aRuntimeIds);
+
+ virtual HRESULT STDMETHODCALLTYPE ConvertReturnedElement(
+ /* [in] */ __RPC__in_opt IRawElementProviderSimple* aRawElmProvider,
+ /* [out] */ __RPC__deref_out_opt IAccessibleEx** aAccEx);
+
+ // IRawElementProviderSimple
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ProviderOptions(
+ /* [retval][out] */ __RPC__out enum ProviderOptions* aProviderOptions);
+
+ virtual HRESULT STDMETHODCALLTYPE GetPatternProvider(
+ /* [in] */ PATTERNID aPatternId,
+ /* [retval][out] */ __RPC__deref_out_opt IUnknown** aPatternProvider);
+
+ virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
+ /* [in] */ PROPERTYID aPropertyId,
+ /* [retval][out] */ __RPC__out VARIANT* aPropertyValue);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HostRawElementProvider(
+ /* [retval][out] */ __RPC__deref_out_opt IRawElementProviderSimple** aRawElmProvider);
+
+private:
+ uiaRawElmProvider() = delete;
+ uiaRawElmProvider& operator =(const uiaRawElmProvider&) = delete;
+ uiaRawElmProvider(const uiaRawElmProvider&) = delete;
+
+protected:
+ RefPtr<AccessibleWrap> mAcc;
+};
+
+} // a11y namespace
+} // mozilla namespace
+
+#endif