summaryrefslogtreecommitdiffstats
path: root/accessible/windows/ia2
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/windows/ia2')
-rw-r--r--accessible/windows/ia2/ia2Accessible.cpp615
-rw-r--r--accessible/windows/ia2/ia2Accessible.h125
-rw-r--r--accessible/windows/ia2/ia2AccessibleAction.cpp152
-rw-r--r--accessible/windows/ia2/ia2AccessibleAction.h84
-rw-r--r--accessible/windows/ia2/ia2AccessibleApplication.cpp94
-rw-r--r--accessible/windows/ia2/ia2AccessibleApplication.h49
-rw-r--r--accessible/windows/ia2/ia2AccessibleComponent.cpp106
-rw-r--r--accessible/windows/ia2/ia2AccessibleComponent.h40
-rw-r--r--accessible/windows/ia2/ia2AccessibleEditableText.cpp107
-rw-r--r--accessible/windows/ia2/ia2AccessibleEditableText.h59
-rw-r--r--accessible/windows/ia2/ia2AccessibleHyperlink.cpp166
-rw-r--r--accessible/windows/ia2/ia2AccessibleHyperlink.h55
-rw-r--r--accessible/windows/ia2/ia2AccessibleHypertext.cpp138
-rw-r--r--accessible/windows/ia2/ia2AccessibleHypertext.h68
-rw-r--r--accessible/windows/ia2/ia2AccessibleImage.cpp81
-rw-r--r--accessible/windows/ia2/ia2AccessibleImage.h51
-rw-r--r--accessible/windows/ia2/ia2AccessibleRelation.cpp94
-rw-r--r--accessible/windows/ia2/ia2AccessibleRelation.h78
-rw-r--r--accessible/windows/ia2/ia2AccessibleTable.cpp570
-rw-r--r--accessible/windows/ia2/ia2AccessibleTable.h178
-rw-r--r--accessible/windows/ia2/ia2AccessibleTableCell.cpp186
-rw-r--r--accessible/windows/ia2/ia2AccessibleTableCell.h71
-rw-r--r--accessible/windows/ia2/ia2AccessibleText.cpp481
-rw-r--r--accessible/windows/ia2/ia2AccessibleText.h255
-rw-r--r--accessible/windows/ia2/ia2AccessibleValue.cpp125
-rw-r--r--accessible/windows/ia2/ia2AccessibleValue.h43
-rw-r--r--accessible/windows/ia2/moz.build61
27 files changed, 4132 insertions, 0 deletions
diff --git a/accessible/windows/ia2/ia2Accessible.cpp b/accessible/windows/ia2/ia2Accessible.cpp
new file mode 100644
index 0000000000..3954d4c307
--- /dev/null
+++ b/accessible/windows/ia2/ia2Accessible.cpp
@@ -0,0 +1,615 @@
+/* -*- 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 "AccAttributes.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 "mozilla/PresShell.h"
+#include "nsISimpleEnumerator.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// ia2Accessible
+////////////////////////////////////////////////////////////////////////////////
+
+STDMETHODIMP
+ia2Accessible::QueryInterface(REFIID iid, void** ppv) {
+ if (!ppv) return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ // NOTE: If any new versions of IAccessible2 are added here, they should
+ // also be added to the IA2 Handler in
+ // /accessible/ipc/win/handler/AccessibleHandler.cpp
+
+ 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)
+ *ppv = static_cast<IAccessible2*>(this);
+
+ if (*ppv) {
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+AccessibleWrap* ia2Accessible::LocalAcc() {
+ return static_cast<MsaaAccessible*>(this)->LocalAcc();
+}
+
+Accessible* ia2Accessible::Acc() {
+ return static_cast<MsaaAccessible*>(this)->Acc();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessible2
+
+STDMETHODIMP
+ia2Accessible::get_nRelations(long* aNRelations) {
+ if (!aNRelations) return E_INVALIDARG;
+ *aNRelations = 0;
+
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ 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;
+}
+
+STDMETHODIMP
+ia2Accessible::get_relation(long aRelationIndex,
+ IAccessibleRelation** aRelation) {
+ if (!aRelation || aRelationIndex < 0) return E_INVALIDARG;
+ *aRelation = nullptr;
+
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ 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) {
+ MsaaAccessible* msaa = static_cast<MsaaAccessible*>(this);
+ msaa->AssociateCOMObjectForDisconnection(ia2Relation);
+ ia2Relation.forget(aRelation);
+ return S_OK;
+ }
+
+ relIdx++;
+ }
+ }
+
+ return E_INVALIDARG;
+}
+
+STDMETHODIMP
+ia2Accessible::get_relations(long aMaxRelations,
+ IAccessibleRelation** aRelation,
+ long* aNRelations) {
+ if (!aRelation || !aNRelations || aMaxRelations <= 0) return E_INVALIDARG;
+ *aNRelations = 0;
+
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ 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()) {
+ MsaaAccessible* msaa = static_cast<MsaaAccessible*>(this);
+ msaa->AssociateCOMObjectForDisconnection(ia2Rel);
+ ia2Rel.forget(aRelation + (*aNRelations));
+ (*aNRelations)++;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2Accessible::role(long* aRole) {
+ if (!aRole) return E_INVALIDARG;
+ *aRole = 0;
+
+ Accessible* acc = Acc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+#define ROLE(_geckoRole, stringRole, atkRole, macRole, macSubrole, msaaRole, \
+ ia2Role, androidClass, nameRule) \
+ case roles::_geckoRole: \
+ *aRole = ia2Role; \
+ break;
+
+ a11y::role geckoRole;
+ 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.
+ if (geckoRole == roles::ROW) {
+ Accessible* xpParent = acc->Parent();
+ if (xpParent && xpParent->Role() == roles::TREE_TABLE)
+ *aRole = ROLE_SYSTEM_OUTLINEITEM;
+ }
+
+ return S_OK;
+}
+
+// XXX Use MOZ_CAN_RUN_SCRIPT_BOUNDARY for now due to bug 1543294.
+MOZ_CAN_RUN_SCRIPT_BOUNDARY STDMETHODIMP
+ia2Accessible::scrollTo(enum IA2ScrollType aScrollType) {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ acc->ScrollTo(aScrollType);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2Accessible::scrollToPoint(enum IA2CoordinateType aCoordType, long aX,
+ long aY) {
+ if (!Acc()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ AccessibleWrap* acc = LocalAcc();
+ if (!acc) {
+ return E_NOTIMPL; // XXX Not supported for RemoteAccessible yet.
+ }
+
+ uint32_t geckoCoordType =
+ (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE)
+ ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
+ : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+
+ acc->ScrollToPoint(geckoCoordType, aX, aY);
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2Accessible::get_groupPosition(long* aGroupLevel, long* aSimilarItemsInGroup,
+ long* aPositionInGroup) {
+ if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup)
+ return E_INVALIDARG;
+
+ *aGroupLevel = 0;
+ *aSimilarItemsInGroup = 0;
+ *aPositionInGroup = 0;
+
+ Accessible* acc = Acc();
+ if (!acc) {
+ 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;
+}
+
+STDMETHODIMP
+ia2Accessible::get_states(AccessibleStates* aStates) {
+ if (!aStates) return E_INVALIDARG;
+ *aStates = 0;
+
+ // XXX: bug 344674 should come with better approach that we have here.
+
+ Accessible* acc = Acc();
+ if (!acc) {
+ *aStates = IA2_STATE_DEFUNCT;
+ return S_OK;
+ }
+
+ uint64_t state;
+ 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;
+}
+
+STDMETHODIMP
+ia2Accessible::get_extendedRole(BSTR* aExtendedRole) {
+ if (!aExtendedRole) return E_INVALIDARG;
+
+ *aExtendedRole = nullptr;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+ia2Accessible::get_localizedExtendedRole(BSTR* aLocalizedExtendedRole) {
+ if (!aLocalizedExtendedRole) return E_INVALIDARG;
+
+ *aLocalizedExtendedRole = nullptr;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+ia2Accessible::get_nExtendedStates(long* aNExtendedStates) {
+ if (!aNExtendedStates) return E_INVALIDARG;
+
+ *aNExtendedStates = 0;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+ia2Accessible::get_extendedStates(long aMaxExtendedStates,
+ BSTR** aExtendedStates,
+ long* aNExtendedStates) {
+ if (!aExtendedStates || !aNExtendedStates) return E_INVALIDARG;
+
+ *aExtendedStates = nullptr;
+ *aNExtendedStates = 0;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+ia2Accessible::get_localizedExtendedStates(long aMaxLocalizedExtendedStates,
+ BSTR** aLocalizedExtendedStates,
+ long* aNLocalizedExtendedStates) {
+ if (!aLocalizedExtendedStates || !aNLocalizedExtendedStates)
+ return E_INVALIDARG;
+
+ *aLocalizedExtendedStates = nullptr;
+ *aNLocalizedExtendedStates = 0;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+ia2Accessible::get_uniqueID(long* aUniqueID) {
+ if (!aUniqueID) return E_INVALIDARG;
+
+ Accessible* acc = Acc();
+ *aUniqueID = MsaaAccessible::GetChildIDFor(acc);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2Accessible::get_windowHandle(HWND* aWindowHandle) {
+ if (!aWindowHandle) return E_INVALIDARG;
+ *aWindowHandle = 0;
+
+ Accessible* acc = Acc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+ *aWindowHandle = MsaaAccessible::GetHWNDFor(acc);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2Accessible::get_indexInParent(long* aIndexInParent) {
+ if (!aIndexInParent) return E_INVALIDARG;
+ *aIndexInParent = -1;
+
+ Accessible* acc = Acc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+ *aIndexInParent = acc->IndexInParent();
+
+ if (*aIndexInParent == -1) return S_FALSE;
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2Accessible::get_locale(IA2Locale* aLocale) {
+ 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.
+
+ if (!Acc()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ AccessibleWrap* acc = LocalAcc();
+ if (!acc) {
+ return E_NOTIMPL; // XXX Not supported for RemoteAccessible yet.
+ }
+
+ 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;
+}
+
+STDMETHODIMP
+ia2Accessible::get_attributes(BSTR* aAttributes) {
+ if (!aAttributes) return E_INVALIDARG;
+ *aAttributes = nullptr;
+
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ // The format is name:value;name:value; with \ for escaping these
+ // characters ":;=,\".
+ RefPtr<AccAttributes> attributes = acc->Attributes();
+ return ConvertToIA2Attributes(attributes, aAttributes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessible2_2
+
+STDMETHODIMP
+ia2Accessible::get_attribute(BSTR name, VARIANT* aAttribute) {
+ if (!aAttribute) return E_INVALIDARG;
+
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible,
+ long* aCaretOffset) {
+ if (!aAccessible || !aCaretOffset) return E_INVALIDARG;
+
+ *aAccessible = nullptr;
+ *aCaretOffset = -1;
+
+ if (!Acc()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ AccessibleWrap* acc = LocalAcc();
+ if (!acc) {
+ return E_NOTIMPL; // XXX Not supported for RemoteAccessible yet.
+ }
+
+ int32_t caretOffset = -1;
+ LocalAccessible* accWithCaret =
+ SelectionMgr()->AccessibleWithCaret(&caretOffset);
+ if (!accWithCaret || acc->Document() != accWithCaret->Document())
+ return S_FALSE;
+
+ LocalAccessible* child = accWithCaret;
+ while (!child->IsDoc() && child != acc) child = child->LocalParent();
+
+ if (child != acc) return S_FALSE;
+
+ RefPtr<IAccessible2> ia2WithCaret;
+ accWithCaret->GetNativeInterface(getter_AddRefs(ia2WithCaret));
+ ia2WithCaret.forget(aAccessible);
+ *aCaretOffset = caretOffset;
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2Accessible::get_relationTargetsOfType(BSTR aType, long aMaxTargets,
+ IUnknown*** aTargets,
+ long* aNTargets) {
+ 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;
+
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ nsTArray<Accessible*> targets;
+ Relation rel = acc->RelationByType(*relationType);
+ Accessible* target = nullptr;
+ while (
+ (target = rel.Next()) &&
+ (aMaxTargets == 0 || 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++) {
+ (*aTargets)[i] = MsaaAccessible::NativeAccessible(targets[i]);
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2Accessible::get_selectionRanges(IA2Range** aRanges, long* aNRanges) {
+ if (!aRanges || !aNRanges) return E_INVALIDARG;
+
+ *aNRanges = 0;
+
+ if (!Acc()) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ AccessibleWrap* acc = LocalAcc();
+ if (!acc) {
+ return E_NOTIMPL; // XXX Not supported for RemoteAccessible yet.
+ }
+
+ AutoTArray<TextRange, 1> ranges;
+ acc->Document()->SelectionRanges(&ranges);
+ ranges.RemoveElementsBy([acc](auto& range) { return !range.Crop(acc); });
+
+ *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++) {
+ RefPtr<IAccessible2> anchor =
+ MsaaAccessible::GetFrom(ranges[idx].StartContainer());
+ anchor.forget(&(*aRanges)[idx].anchor);
+
+ (*aRanges)[idx].anchorOffset = ranges[idx].StartOffset();
+
+ RefPtr<IAccessible2> active =
+ MsaaAccessible::GetFrom(ranges[idx].EndContainer());
+ active.forget(&(*aRanges)[idx].active);
+
+ (*aRanges)[idx].activeOffset = ranges[idx].EndOffset();
+ }
+
+ return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+static inline void EscapeAttributeChars(nsString& aStr) {
+ int32_t offset = 0;
+ static const char16_t kCharsToEscape[] = u":;=,\\";
+ while ((offset = aStr.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
+ aStr.Insert('\\', offset);
+ offset += 2;
+ }
+}
+
+HRESULT
+ia2Accessible::ConvertToIA2Attributes(AccAttributes* aAttributes,
+ BSTR* aIA2Attributes) {
+ *aIA2Attributes = nullptr;
+
+ // The format is name:value;name:value; with \ for escaping these
+ // characters ":;=,\".
+
+ if (!aAttributes) return S_FALSE;
+
+ nsAutoString strAttrs;
+
+ for (auto iter : *aAttributes) {
+ nsAutoString name;
+ iter.NameAsString(name);
+ EscapeAttributeChars(name);
+
+ nsAutoString value;
+ iter.ValueAsString(value);
+ EscapeAttributeChars(value);
+
+ strAttrs.Append(name);
+ 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 0000000000..0015a45c23
--- /dev/null
+++ b/accessible/windows/ia2/ia2Accessible.h
@@ -0,0 +1,125 @@
+/* -*- 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 "nsTArray.h"
+
+#include "Accessible2_3.h"
+
+namespace mozilla {
+namespace a11y {
+class Accessible;
+class AccAttributes;
+class AccessibleWrap;
+
+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(AccAttributes* aAttributes,
+ BSTR* aIA2Attributes);
+
+ private:
+ AccessibleWrap* LocalAcc();
+ Accessible* Acc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleAction.cpp b/accessible/windows/ia2/ia2AccessibleAction.cpp
new file mode 100644
index 0000000000..d89bd79ce1
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleAction.cpp
@@ -0,0 +1,152 @@
+/* -*- 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;
+
+Accessible* ia2AccessibleAction::Acc() {
+ return static_cast<MsaaAccessible*>(this)->Acc();
+}
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv) {
+ if (!ppv) return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleAction == iid) {
+ *ppv = static_cast<IAccessibleAction*>(this);
+ (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+// IAccessibleAction
+
+STDMETHODIMP
+ia2AccessibleAction::nActions(long* aActionCount) {
+ if (!aActionCount) return E_INVALIDARG;
+
+ *aActionCount = 0;
+
+ Accessible* acc = Acc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+ *aActionCount = acc->ActionCount();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleAction::doAction(long aActionIndex) {
+ Accessible* acc = Acc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+ uint8_t index = static_cast<uint8_t>(aActionIndex);
+ return acc->DoAction(index) ? S_OK : E_INVALIDARG;
+}
+
+STDMETHODIMP
+ia2AccessibleAction::get_description(long aActionIndex, BSTR* aDescription) {
+ if (!aDescription) return E_INVALIDARG;
+ *aDescription = nullptr;
+
+ Accessible* acc = Acc();
+ if (!acc) 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;
+}
+
+STDMETHODIMP
+ia2AccessibleAction::get_keyBinding(long aActionIndex, long aNumMaxBinding,
+ BSTR** aKeyBinding, long* aNumBinding) {
+ if (!aKeyBinding) return E_INVALIDARG;
+ *aKeyBinding = nullptr;
+
+ if (!aNumBinding) return E_INVALIDARG;
+ *aNumBinding = 0;
+
+ if (aActionIndex != 0 || aNumMaxBinding < 1) return E_INVALIDARG;
+
+ Accessible* acc = Acc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+ // Expose KeyboardShortcut if it's not exposed via MSAA accKeyboardShortcut.
+ LocalAccessible* localAcc = acc->AsLocal();
+ if (!localAcc) {
+ // RemoteAccessibles can't have a KeyboardShortcut.
+ return S_FALSE;
+ }
+
+ KeyBinding keyBinding = acc->AccessKey();
+ if (keyBinding.IsEmpty()) {
+ // In this case, KeyboardShortcut will be exposed via MSAA
+ // accKeyboardShortcut.
+ return S_FALSE;
+ }
+
+ // MSAA accKeyboardShortcut will expose AccessKey.
+ keyBinding = localAcc->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;
+}
+
+STDMETHODIMP
+ia2AccessibleAction::get_name(long aActionIndex, BSTR* aName) {
+ if (!aName) return E_INVALIDARG;
+
+ *aName = nullptr;
+
+ Accessible* acc = Acc();
+ if (!acc) 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;
+}
+
+STDMETHODIMP
+ia2AccessibleAction::get_localizedName(long aActionIndex,
+ BSTR* aLocalizedName) {
+ if (!aLocalizedName) return E_INVALIDARG;
+
+ *aLocalizedName = nullptr;
+ return E_NOTIMPL;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleAction.h b/accessible/windows/ia2/ia2AccessibleAction.h
new file mode 100644
index 0000000000..99f259083a
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleAction.h
@@ -0,0 +1,84 @@
+/* -*- 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);
+
+ private:
+ Accessible* Acc();
+};
+
+} // 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/ia2AccessibleApplication.cpp b/accessible/windows/ia2/ia2AccessibleApplication.cpp
new file mode 100644
index 0000000000..7844e97074
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleApplication.cpp
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "ia2AccessibleApplication.h"
+
+#include "AccessibleApplication_i.c"
+#include "ApplicationAccessibleWrap.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+ApplicationAccessible* ia2AccessibleApplication::AppAcc() {
+ return static_cast<ApplicationAccessible*>(LocalAcc());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IUnknown
+
+IMPL_IUNKNOWN_QUERY_HEAD(ia2AccessibleApplication)
+IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleApplication)
+IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(MsaaAccessible)
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessibleApplication
+
+STDMETHODIMP
+ia2AccessibleApplication::get_appName(BSTR* aName) {
+ if (!aName) return E_INVALIDARG;
+
+ *aName = nullptr;
+
+ ApplicationAccessible* appAcc = AppAcc();
+ if (!appAcc) return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString name;
+ appAcc->AppName(name);
+ if (name.IsEmpty()) return S_FALSE;
+
+ *aName = ::SysAllocStringLen(name.get(), name.Length());
+ return *aName ? S_OK : E_OUTOFMEMORY;
+}
+
+STDMETHODIMP
+ia2AccessibleApplication::get_appVersion(BSTR* aVersion) {
+ if (!aVersion) return E_INVALIDARG;
+
+ *aVersion = nullptr;
+
+ ApplicationAccessible* appAcc = AppAcc();
+ if (!appAcc) return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString version;
+ appAcc->AppVersion(version);
+ if (version.IsEmpty()) return S_FALSE;
+
+ *aVersion = ::SysAllocStringLen(version.get(), version.Length());
+ return *aVersion ? S_OK : E_OUTOFMEMORY;
+}
+
+STDMETHODIMP
+ia2AccessibleApplication::get_toolkitName(BSTR* aName) {
+ if (!aName) return E_INVALIDARG;
+
+ ApplicationAccessible* appAcc = AppAcc();
+ if (!appAcc) return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString name;
+ appAcc->PlatformName(name);
+ if (name.IsEmpty()) return S_FALSE;
+
+ *aName = ::SysAllocStringLen(name.get(), name.Length());
+ return *aName ? S_OK : E_OUTOFMEMORY;
+}
+
+STDMETHODIMP
+ia2AccessibleApplication::get_toolkitVersion(BSTR* aVersion) {
+ if (!aVersion) return E_INVALIDARG;
+
+ *aVersion = nullptr;
+
+ ApplicationAccessible* appAcc = AppAcc();
+ if (!appAcc) return CO_E_OBJNOTCONNECTED;
+
+ nsAutoString version;
+ appAcc->PlatformVersion(version);
+ if (version.IsEmpty()) return S_FALSE;
+
+ *aVersion = ::SysAllocStringLen(version.get(), version.Length());
+ return *aVersion ? S_OK : E_OUTOFMEMORY;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleApplication.h b/accessible/windows/ia2/ia2AccessibleApplication.h
new file mode 100644
index 0000000000..283dc38471
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleApplication.h
@@ -0,0 +1,49 @@
+/* -*- 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_APPLICATION_H_
+#define IA2_ACCESSIBLE_APPLICATION_H_
+
+#include "AccessibleApplication.h"
+#include "IUnknownImpl.h"
+#include "MsaaAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+class ApplicationAccessible;
+
+class ia2AccessibleApplication : public IAccessibleApplication,
+ public MsaaAccessible {
+ public:
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+ IMPL_IUNKNOWN_REFCOUNTING_INHERITED(MsaaAccessible)
+
+ // 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);
+
+ protected:
+ using MsaaAccessible::MsaaAccessible;
+
+ private:
+ ApplicationAccessible* AppAcc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleComponent.cpp b/accessible/windows/ia2/ia2AccessibleComponent.cpp
new file mode 100644
index 0000000000..9c22a66cad
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleComponent.cpp
@@ -0,0 +1,106 @@
+/* -*- 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;
+
+AccessibleWrap* ia2AccessibleComponent::LocalAcc() {
+ return static_cast<MsaaAccessible*>(this)->LocalAcc();
+}
+
+// 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) {
+ if (!aX || !aY) return E_INVALIDARG;
+
+ *aX = 0;
+ *aY = 0;
+
+ AccessibleWrap* acc = LocalAcc();
+ if (!acc) 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;
+
+ LayoutDeviceIntRect 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->LocalParent()) {
+ *aX = rect.X();
+ *aY = rect.Y();
+ return S_OK;
+ }
+
+ // The coordinates of the bounding box are given relative to the parent's
+ // coordinate system.
+ LayoutDeviceIntRect parentRect = acc->LocalParent()->Bounds();
+ *aX = rect.X() - parentRect.X();
+ *aY = rect.Y() - parentRect.Y();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleComponent::get_foreground(IA2Color* aForeground) {
+ if (!aForeground) return E_INVALIDARG;
+
+ *aForeground = 0;
+
+ AccessibleWrap* acc = LocalAcc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+ nsIFrame* frame = acc->GetFrame();
+ if (frame) *aForeground = frame->StyleText()->mColor.ToColor();
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleComponent::get_background(IA2Color* aBackground) {
+ if (!aBackground) return E_INVALIDARG;
+
+ *aBackground = 0;
+
+ AccessibleWrap* acc = LocalAcc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+ nsIFrame* frame = acc->GetFrame();
+ if (frame) {
+ *aBackground = frame->StyleBackground()->BackgroundColor(frame);
+ }
+
+ return S_OK;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleComponent.h b/accessible/windows/ia2/ia2AccessibleComponent.h
new file mode 100644
index 0000000000..507bbbd628
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleComponent.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 IA2_ACCESSIBLE_COMPONENT_H_
+#define IA2_ACCESSIBLE_COMPONENT_H_
+
+#include "AccessibleComponent.h"
+
+namespace mozilla {
+namespace a11y {
+class AccessibleWrap;
+
+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);
+
+ private:
+ AccessibleWrap* LocalAcc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleEditableText.cpp b/accessible/windows/ia2/ia2AccessibleEditableText.cpp
new file mode 100644
index 0000000000..586ac1f626
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleEditableText.cpp
@@ -0,0 +1,107 @@
+/* -*- 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 "ia2AccessibleHypertext.h"
+
+#include "AccessibleEditableText_i.c"
+#include "HyperTextAccessible-inl.h"
+#include "HyperTextAccessibleWrap.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+using namespace mozilla::a11y;
+
+HyperTextAccessibleWrap* ia2AccessibleEditableText::TextAcc() {
+ auto hyp = static_cast<ia2AccessibleHypertext*>(this);
+ AccessibleWrap* acc = static_cast<MsaaAccessible*>(hyp)->LocalAcc();
+ return static_cast<HyperTextAccessibleWrap*>(acc);
+}
+
+// IAccessibleEditableText
+
+STDMETHODIMP
+ia2AccessibleEditableText::copyText(long aStartOffset, long aEndOffset) {
+ HyperTextAccessible* textAcc = TextAcc();
+ if (!textAcc) return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG;
+
+ textAcc->CopyText(aStartOffset, aEndOffset);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::deleteText(long aStartOffset, long aEndOffset) {
+ HyperTextAccessible* textAcc = TextAcc();
+ if (!textAcc) return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG;
+
+ textAcc->DeleteText(aStartOffset, aEndOffset);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::insertText(long aOffset, BSTR* aText) {
+ uint32_t length = ::SysStringLen(*aText);
+ nsAutoString text(*aText, length);
+
+ HyperTextAccessible* textAcc = TextAcc();
+ if (!textAcc) return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
+
+ textAcc->InsertText(text, aOffset);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::cutText(long aStartOffset, long aEndOffset) {
+ HyperTextAccessible* textAcc = TextAcc();
+ if (!textAcc) return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG;
+
+ textAcc->CutText(aStartOffset, aEndOffset);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::pasteText(long aOffset) {
+ RefPtr<HyperTextAccessible> textAcc = TextAcc();
+ if (!textAcc) return CO_E_OBJNOTCONNECTED;
+
+ if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
+
+ textAcc->PasteText(aOffset);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleEditableText::replaceText(long aStartOffset, long aEndOffset,
+ BSTR* aText) {
+ HyperTextAccessible* textAcc = TextAcc();
+ if (!textAcc) 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;
+}
+
+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 0000000000..11029c1759
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleEditableText.h
@@ -0,0 +1,59 @@
+/* -*- 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 HyperTextAccessibleWrap;
+
+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);
+
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY
+ 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);
+
+ private:
+ HyperTextAccessibleWrap* TextAcc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleHyperlink.cpp b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp
new file mode 100644
index 0000000000..6a49508da9
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp
@@ -0,0 +1,166 @@
+/* -*- 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 "AccessibleHyperlink.h"
+#include "AccessibleHyperlink_i.c"
+
+#include "AccessibleWrap.h"
+#include "IUnknownImpl.h"
+#include "nsIURI.h"
+
+using namespace mozilla::a11y;
+
+Accessible* ia2AccessibleHyperlink::Acc() {
+ return static_cast<MsaaAccessible*>(this)->Acc();
+}
+
+AccessibleWrap* ia2AccessibleHyperlink::LocalAcc() {
+ return static_cast<MsaaAccessible*>(this)->LocalAcc();
+}
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleHyperlink::QueryInterface(REFIID iid, void** ppv) {
+ if (!ppv) return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleHyperlink == iid) {
+ Accessible* acc = Acc();
+ if (!acc || !acc->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) {
+ if (!aAnchor) return E_INVALIDARG;
+
+ VariantInit(aAnchor);
+
+ LocalAccessible* thisObj = LocalAcc();
+ if (!thisObj) {
+ 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;
+
+ RefPtr<IAccessible> result;
+ anchor->GetNativeInterface(getter_AddRefs(result));
+ result.forget(&aAnchor->punkVal);
+ aAnchor->vt = VT_UNKNOWN;
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleHyperlink::get_anchorTarget(long aIndex, VARIANT* aAnchorTarget) {
+ if (!aAnchorTarget) {
+ return E_INVALIDARG;
+ }
+
+ VariantInit(aAnchorTarget);
+
+ LocalAccessible* thisObj = LocalAcc();
+ if (!thisObj) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ nsAutoCString uriStr;
+
+ 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;
+}
+
+STDMETHODIMP
+ia2AccessibleHyperlink::get_startIndex(long* aIndex) {
+ if (!aIndex) return E_INVALIDARG;
+
+ *aIndex = 0;
+
+ Accessible* thisObj = Acc();
+ if (!thisObj) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (!thisObj->IsLink()) return S_FALSE;
+
+ *aIndex = thisObj->StartOffset();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleHyperlink::get_endIndex(long* aIndex) {
+ if (!aIndex) return E_INVALIDARG;
+
+ *aIndex = 0;
+
+ Accessible* thisObj = Acc();
+ if (!thisObj) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (!thisObj->IsLink()) return S_FALSE;
+
+ *aIndex = thisObj->EndOffset();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleHyperlink::get_valid(boolean* aValid) {
+ if (!aValid) return E_INVALIDARG;
+
+ *aValid = false;
+
+ LocalAccessible* thisObj = LocalAcc();
+ if (!thisObj) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (!thisObj->IsLink()) return S_FALSE;
+
+ *aValid = thisObj->IsLinkValid();
+ return S_OK;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleHyperlink.h b/accessible/windows/ia2/ia2AccessibleHyperlink.h
new file mode 100644
index 0000000000..e7a2c5a0e2
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleHyperlink.h
@@ -0,0 +1,55 @@
+/* -*- 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 Accessible;
+class AccessibleWrap;
+
+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);
+
+ private:
+ Accessible* Acc();
+ AccessibleWrap* LocalAcc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleHypertext.cpp b/accessible/windows/ia2/ia2AccessibleHypertext.cpp
new file mode 100644
index 0000000000..220071c883
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleHypertext.cpp
@@ -0,0 +1,138 @@
+/* -*- 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 "IUnknownImpl.h"
+
+using namespace mozilla::a11y;
+
+HyperTextAccessibleBase* ia2AccessibleHypertext::TextAcc() {
+ Accessible* acc = Acc();
+ return acc ? acc->AsHyperTextBase() : nullptr;
+}
+
+// IUnknown
+STDMETHODIMP
+ia2AccessibleHypertext::QueryInterface(REFIID aIID, void** aInstancePtr) {
+ if (!aInstancePtr) return E_FAIL;
+
+ *aInstancePtr = nullptr;
+
+ Accessible* acc = Acc();
+ if (acc && acc->IsTextRole()) {
+ bool isLocal = acc->IsLocal();
+ 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_IAccessibleHypertext2 && isLocal) {
+ *aInstancePtr = static_cast<IAccessibleHypertext2*>(this);
+ } else if (aIID == IID_IAccessibleEditableText && isLocal) {
+ *aInstancePtr = static_cast<IAccessibleEditableText*>(this);
+ }
+
+ if (*aInstancePtr) {
+ AddRef();
+ return S_OK;
+ }
+ }
+
+ return MsaaAccessible::QueryInterface(aIID, aInstancePtr);
+}
+
+// IAccessibleHypertext
+
+STDMETHODIMP
+ia2AccessibleHypertext::get_nHyperlinks(long* aHyperlinkCount) {
+ if (!aHyperlinkCount) return E_INVALIDARG;
+
+ *aHyperlinkCount = 0;
+
+ HyperTextAccessibleBase* hyperText = TextAcc();
+ if (!hyperText) return CO_E_OBJNOTCONNECTED;
+
+ *aHyperlinkCount = hyperText->LinkCount();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleHypertext::get_hyperlink(long aLinkIndex,
+ IAccessibleHyperlink** aHyperlink) {
+ if (!aHyperlink) return E_INVALIDARG;
+
+ *aHyperlink = nullptr;
+
+ HyperTextAccessibleBase* hyperText = TextAcc();
+ if (!hyperText) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ Accessible* hyperLink = hyperText->LinkAt(aLinkIndex);
+
+ if (!hyperLink) return E_FAIL;
+
+ RefPtr<IAccessibleHyperlink> result = MsaaAccessible::GetFrom(hyperLink);
+ result.forget(aHyperlink);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleHypertext::get_hyperlinkIndex(long aCharIndex,
+ long* aHyperlinkIndex) {
+ if (!aHyperlinkIndex) return E_INVALIDARG;
+
+ *aHyperlinkIndex = 0;
+
+ HyperTextAccessibleBase* hyperAcc = TextAcc();
+ if (!hyperAcc) return CO_E_OBJNOTCONNECTED;
+
+ *aHyperlinkIndex = hyperAcc->LinkIndexAtOffset(aCharIndex);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleHypertext::get_hyperlinks(IAccessibleHyperlink*** aHyperlinks,
+ long* aNHyperlinks) {
+ if (!aHyperlinks || !aNHyperlinks) {
+ return E_INVALIDARG;
+ }
+
+ *aHyperlinks = nullptr;
+ *aNHyperlinks = 0;
+
+ HyperTextAccessibleBase* hyperText = TextAcc();
+ if (!hyperText) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ uint32_t count = hyperText->LinkCount();
+ *aNHyperlinks = count;
+
+ if (count == 0) {
+ *aHyperlinks = nullptr;
+ return S_FALSE;
+ }
+
+ *aHyperlinks = static_cast<IAccessibleHyperlink**>(
+ ::CoTaskMemAlloc(sizeof(IAccessibleHyperlink*) * count));
+ if (!*aHyperlinks) {
+ return E_OUTOFMEMORY;
+ }
+
+ for (uint32_t i = 0; i < count; ++i) {
+ Accessible* hyperLink = hyperText->LinkAt(i);
+ MOZ_ASSERT(hyperLink);
+ RefPtr<IAccessibleHyperlink> iaHyper = MsaaAccessible::GetFrom(hyperLink);
+ iaHyper.forget(&(*aHyperlinks)[i]);
+ }
+
+ return S_OK;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleHypertext.h b/accessible/windows/ia2/ia2AccessibleHypertext.h
new file mode 100644
index 0000000000..2defbc8eeb
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleHypertext.h
@@ -0,0 +1,68 @@
+/* -*- 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 "ia2AccessibleEditableText.h"
+#include "ia2AccessibleText.h"
+#include "AccessibleHypertext2.h"
+#include "IUnknownImpl.h"
+#include "MsaaAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+class HyperTextAccessibleBase;
+
+class ia2AccessibleHypertext : public ia2AccessibleText,
+ public IAccessibleHypertext2,
+ public ia2AccessibleEditableText,
+ public MsaaAccessible {
+ public:
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+ IMPL_IUNKNOWN_REFCOUNTING_INHERITED(MsaaAccessible)
+
+ // IAccessible2
+ // We indirectly inherit IAccessible2, which has a get_attributes method,
+ // but IAccessibleText also has a get_attributes method with a different
+ // signature. We want both.
+ using MsaaAccessible::get_attributes;
+
+ // 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);
+
+ // IAccessibleHypertext2
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlinks(
+ /* [out, size_is(,*nHyperlinks)] */ IAccessibleHyperlink*** hyperlinks,
+ /* [out, retval] */ long* nHyperlinks);
+
+ protected:
+ using MsaaAccessible::MsaaAccessible;
+
+ private:
+ HyperTextAccessibleBase* TextAcc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleImage.cpp b/accessible/windows/ia2/ia2AccessibleImage.cpp
new file mode 100644
index 0000000000..529269b566
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleImage.cpp
@@ -0,0 +1,81 @@
+/* -*- 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 "ImageAccessible.h"
+#include "IUnknownImpl.h"
+#include "nsIAccessibleTypes.h"
+
+#include "nsString.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+// IUnknown
+IMPL_IUNKNOWN_QUERY_HEAD(ia2AccessibleImage)
+IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleImage)
+IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(MsaaAccessible)
+
+// IAccessibleImage
+
+STDMETHODIMP
+ia2AccessibleImage::get_description(BSTR* aDescription) {
+ if (!aDescription) return E_INVALIDARG;
+
+ *aDescription = nullptr;
+
+ Accessible* acc = Acc();
+ if (!acc) 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;
+}
+
+STDMETHODIMP
+ia2AccessibleImage::get_imagePosition(enum IA2CoordinateType aCoordType,
+ long* aX, long* aY) {
+ if (!aX || !aY) return E_INVALIDARG;
+
+ *aX = 0;
+ *aY = 0;
+
+ Accessible* acc = Acc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+ uint32_t geckoCoordType =
+ (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE)
+ ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
+ : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+
+ LayoutDeviceIntPoint pos = acc->Position(geckoCoordType);
+ *aX = pos.x;
+ *aY = pos.y;
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleImage::get_imageSize(long* aHeight, long* aWidth) {
+ if (!aHeight || !aWidth) return E_INVALIDARG;
+
+ *aHeight = 0;
+ *aWidth = 0;
+
+ Accessible* acc = Acc();
+ if (!acc) return CO_E_OBJNOTCONNECTED;
+
+ LayoutDeviceIntSize size = acc->Size();
+ *aHeight = size.width;
+ *aWidth = size.height;
+ return S_OK;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleImage.h b/accessible/windows/ia2/ia2AccessibleImage.h
new file mode 100644
index 0000000000..6302130b3a
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleImage.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_IMAGE_H
+#define _ACCESSIBLE_IMAGE_H
+
+#include "AccessibleImage.h"
+#include "IUnknownImpl.h"
+#include "MsaaAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+class ImageAccessible;
+
+class ia2AccessibleImage : public IAccessibleImage, public MsaaAccessible {
+ public:
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+ IMPL_IUNKNOWN_REFCOUNTING_INHERITED(MsaaAccessible)
+
+ // IAccessibleAction
+ // We indirectly inherit IAccessibleAction, which has a get_description
+ // method, but IAccessibleImage also has a get_description method with a
+ // different signature. We want both.
+ using MsaaAccessible::get_description;
+
+ // 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);
+
+ protected:
+ using MsaaAccessible::MsaaAccessible;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleRelation.cpp b/accessible/windows/ia2/ia2AccessibleRelation.cpp
new file mode 100644
index 0000000000..007ca63aa6
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleRelation.cpp
@@ -0,0 +1,94 @@
+/* -*- 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(
+ already_AddRefed(MsaaAccessible::NativeAccessible(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) {
+ 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;
+}
+
+STDMETHODIMP
+ia2AccessibleRelation::get_localizedRelationType(BSTR* aLocalizedRelationType) {
+ if (!aLocalizedRelationType) return E_INVALIDARG;
+
+ *aLocalizedRelationType = nullptr;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+ia2AccessibleRelation::get_nTargets(long* aNTargets) {
+ if (!aNTargets) return E_INVALIDARG;
+
+ *aNTargets = mTargets.Length();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleRelation::get_target(long aTargetIndex, IUnknown** aTarget) {
+ if (aTargetIndex < 0 || (uint32_t)aTargetIndex >= mTargets.Length() ||
+ !aTarget)
+ return E_INVALIDARG;
+
+ RefPtr<IUnknown> target = mTargets[aTargetIndex];
+ target.forget(aTarget);
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleRelation::get_targets(long aMaxTargets, IUnknown** aTargets,
+ long* aNTargets) {
+ 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;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleRelation.h b/accessible/windows/ia2/ia2AccessibleRelation.h
new file mode 100644
index 0000000000..63276b8e00
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleRelation.h
@@ -0,0 +1,78 @@
+/* -*- 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 "MsaaAccessible.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);
+
+ // 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<IUnknown>> 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 0000000000..4dc4398008
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleTable.cpp
@@ -0,0 +1,570 @@
+/* -*- 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 "IUnknownImpl.h"
+#include "mozilla/a11y/Accessible.h"
+#include "mozilla/a11y/TableAccessibleBase.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "Statistics.h"
+
+using namespace mozilla::a11y;
+
+TableAccessibleBase* ia2AccessibleTable::TableAcc() {
+ Accessible* acc = Acc();
+ return acc ? acc->AsTableBase() : nullptr;
+}
+
+// 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 ia2AccessibleHypertext::QueryInterface(iid, ppv);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessibleTable
+
+STDMETHODIMP
+ia2AccessibleTable::get_accessibleAt(long aRowIdx, long aColIdx,
+ IUnknown** aAccessible) {
+ return get_cellAt(aRowIdx, aColIdx, aAccessible);
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_caption(IUnknown** aAccessible) {
+ if (!aAccessible) return E_INVALIDARG;
+
+ *aAccessible = nullptr;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ Accessible* caption = table->Caption();
+ if (!caption) return S_FALSE;
+
+ RefPtr<IAccessible> result = MsaaAccessible::GetFrom(caption);
+ result.forget(aAccessible);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_childIndex(long aRowIdx, long aColIdx,
+ long* aChildIdx) {
+ if (!aChildIdx) return E_INVALIDARG;
+
+ *aChildIdx = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || aColIdx < 0 ||
+ static_cast<uint32_t>(aRowIdx) >= table->RowCount() ||
+ static_cast<uint32_t>(aColIdx) >= table->ColCount())
+ return E_INVALIDARG;
+
+ *aChildIdx = table->CellIndexAt(aRowIdx, aColIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_columnDescription(long aColIdx, BSTR* aDescription) {
+ if (!aDescription) return E_INVALIDARG;
+
+ *aDescription = nullptr;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
+ return E_INVALIDARG;
+
+ nsAutoString descr;
+ table->ColDescription(aColIdx, descr);
+ if (descr.IsEmpty()) return S_FALSE;
+
+ *aDescription = ::SysAllocStringLen(descr.get(), descr.Length());
+ return *aDescription ? S_OK : E_OUTOFMEMORY;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_columnExtentAt(long aRowIdx, long aColIdx,
+ long* aSpan) {
+ if (!aSpan) return E_INVALIDARG;
+
+ *aSpan = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || aColIdx < 0 ||
+ static_cast<uint32_t>(aRowIdx) >= table->RowCount() ||
+ static_cast<uint32_t>(aColIdx) >= table->ColCount())
+ return E_INVALIDARG;
+
+ *aSpan = table->ColExtentAt(aRowIdx, aColIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_columnHeader(IAccessibleTable** aAccessibleTable,
+ long* aStartingRowIndex) {
+ if (!aAccessibleTable || !aStartingRowIndex) return E_INVALIDARG;
+
+ *aAccessibleTable = nullptr;
+ *aStartingRowIndex = -1;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_columnIndex(long aCellIdx, long* aColIdx) {
+ if (!aColIdx) return E_INVALIDARG;
+
+ *aColIdx = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aCellIdx < 0) {
+ return E_INVALIDARG;
+ }
+
+ long colIdx = table->ColIndexAt(aCellIdx);
+ if (colIdx == -1) { // Indicates an error.
+ return E_INVALIDARG;
+ }
+
+ *aColIdx = colIdx;
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nColumns(long* aColCount) {
+ if (!aColCount) return E_INVALIDARG;
+
+ *aColCount = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ *aColCount = table->ColCount();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nRows(long* aRowCount) {
+ if (!aRowCount) return E_INVALIDARG;
+
+ *aRowCount = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ *aRowCount = table->RowCount();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nSelectedChildren(long* aChildCount) {
+ return get_nSelectedCells(aChildCount);
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nSelectedColumns(long* aColCount) {
+ if (!aColCount) return E_INVALIDARG;
+
+ *aColCount = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ *aColCount = table->SelectedColCount();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nSelectedRows(long* aRowCount) {
+ if (!aRowCount) return E_INVALIDARG;
+
+ *aRowCount = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ *aRowCount = table->SelectedRowCount();
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowDescription(long aRowIdx, BSTR* aDescription) {
+ if (!aDescription) return E_INVALIDARG;
+
+ *aDescription = nullptr;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+ return E_INVALIDARG;
+
+ nsAutoString descr;
+ table->RowDescription(aRowIdx, descr);
+ if (descr.IsEmpty()) return S_FALSE;
+
+ *aDescription = ::SysAllocStringLen(descr.get(), descr.Length());
+ return *aDescription ? S_OK : E_OUTOFMEMORY;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowExtentAt(long aRowIdx, long aColIdx, long* aSpan) {
+ if (!aSpan) return E_INVALIDARG;
+
+ *aSpan = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || aColIdx < 0 ||
+ static_cast<uint32_t>(aRowIdx) >= table->RowCount() ||
+ static_cast<uint32_t>(aColIdx) >= table->ColCount())
+ return E_INVALIDARG;
+
+ *aSpan = table->RowExtentAt(aRowIdx, aColIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowHeader(IAccessibleTable** aAccessibleTable,
+ long* aStartingColumnIndex) {
+ if (!aAccessibleTable || !aStartingColumnIndex) return E_INVALIDARG;
+
+ *aAccessibleTable = nullptr;
+ *aStartingColumnIndex = -1;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowIndex(long aCellIdx, long* aRowIdx) {
+ if (!aRowIdx) return E_INVALIDARG;
+
+ *aRowIdx = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aCellIdx < 0) {
+ return E_INVALIDARG;
+ }
+
+ long rowIdx = table->RowIndexAt(aCellIdx);
+ if (rowIdx == -1) { // Indicates an error.
+ return E_INVALIDARG;
+ }
+
+ *aRowIdx = rowIdx;
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedChildren(long aMaxChildren, long** aChildren,
+ long* aNChildren) {
+ if (!aChildren || !aNChildren) return E_INVALIDARG;
+
+ *aChildren = nullptr;
+ *aNChildren = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<uint32_t, 30> cellIndices;
+ table->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;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedColumns(long aMaxColumns, long** aColumns,
+ long* aNColumns) {
+ return get_selectedColumns(aColumns, aNColumns);
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedRows(long aMaxRows, long** aRows,
+ long* aNRows) {
+ return get_selectedRows(aRows, aNRows);
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_summary(IUnknown** aAccessible) {
+ 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;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_isColumnSelected(long aColIdx, boolean* aIsSelected) {
+ if (!aIsSelected) return E_INVALIDARG;
+
+ *aIsSelected = false;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
+ return E_INVALIDARG;
+
+ *aIsSelected = table->IsColSelected(aColIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_isRowSelected(long aRowIdx, boolean* aIsSelected) {
+ if (!aIsSelected) return E_INVALIDARG;
+
+ *aIsSelected = false;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+ return E_INVALIDARG;
+
+ *aIsSelected = table->IsRowSelected(aRowIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_isSelected(long aRowIdx, long aColIdx,
+ boolean* aIsSelected) {
+ if (!aIsSelected) return E_INVALIDARG;
+
+ *aIsSelected = false;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || aColIdx < 0 ||
+ static_cast<uint32_t>(aColIdx) >= table->ColCount() ||
+ static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+ return E_INVALIDARG;
+
+ *aIsSelected = table->IsCellSelected(aRowIdx, aColIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::selectRow(long aRowIdx) {
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+ return E_INVALIDARG;
+
+ table->SelectRow(aRowIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::selectColumn(long aColIdx) {
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
+ return E_INVALIDARG;
+
+ table->SelectCol(aColIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::unselectRow(long aRowIdx) {
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+ return E_INVALIDARG;
+
+ table->UnselectRow(aRowIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::unselectColumn(long aColIdx) {
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
+ return E_INVALIDARG;
+
+ table->UnselectCol(aColIdx);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_rowColumnExtentsAtIndex(long aCellIdx, long* aRowIdx,
+ long* aColIdx,
+ long* aRowExtents,
+ long* aColExtents,
+ boolean* aIsSelected) {
+ if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected)
+ return E_INVALIDARG;
+
+ *aRowIdx = 0;
+ *aColIdx = 0;
+ *aRowExtents = 0;
+ *aColExtents = 0;
+ *aIsSelected = false;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ if (aCellIdx < 0) {
+ return E_INVALIDARG;
+ }
+
+ int32_t colIdx = 0, rowIdx = 0;
+ table->RowAndColIndicesAt(aCellIdx, &rowIdx, &colIdx);
+ if (rowIdx == -1 || colIdx == -1) { // Indicates an error.
+ return E_INVALIDARG;
+ }
+
+ *aRowIdx = rowIdx;
+ *aColIdx = colIdx;
+ *aRowExtents = table->RowExtentAt(rowIdx, colIdx);
+ *aColExtents = table->ColExtentAt(rowIdx, colIdx);
+ *aIsSelected = table->IsCellSelected(rowIdx, colIdx);
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_modelChange(IA2TableModelChange* aModelChange) {
+ return E_NOTIMPL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessibleTable2
+
+STDMETHODIMP
+ia2AccessibleTable::get_cellAt(long aRowIdx, long aColIdx, IUnknown** aCell) {
+ if (!aCell) return E_INVALIDARG;
+
+ *aCell = nullptr;
+
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ Accessible* cell = table->CellAt(aRowIdx, aColIdx);
+ if (!cell) return E_INVALIDARG;
+
+ RefPtr<IAccessible> result = MsaaAccessible::GetFrom(cell);
+ result.forget(aCell);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_nSelectedCells(long* aCellCount) {
+ if (!aCellCount) return E_INVALIDARG;
+
+ *aCellCount = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ *aCellCount = table->SelectedCellCount();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedCells(IUnknown*** aCells,
+ long* aNSelectedCells) {
+ if (!aCells || !aNSelectedCells) return E_INVALIDARG;
+
+ *aCells = nullptr;
+ *aNSelectedCells = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<Accessible*, 30> cells;
+ table->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++) {
+ RefPtr<IAccessible> cell = MsaaAccessible::GetFrom(cells[i]);
+ cell.forget(&(*aCells)[i]);
+ }
+
+ *aNSelectedCells = cells.Length();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedColumns(long** aColumns, long* aNColumns) {
+ if (!aColumns || !aNColumns) return E_INVALIDARG;
+
+ *aColumns = nullptr;
+ *aNColumns = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<uint32_t, 30> colIndices;
+ table->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;
+}
+
+STDMETHODIMP
+ia2AccessibleTable::get_selectedRows(long** aRows, long* aNRows) {
+ if (!aRows || !aNRows) return E_INVALIDARG;
+
+ *aRows = nullptr;
+ *aNRows = 0;
+ TableAccessibleBase* table = TableAcc();
+ if (!table) return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<uint32_t, 30> rowIndices;
+ table->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;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleTable.h b/accessible/windows/ia2/ia2AccessibleTable.h
new file mode 100644
index 0000000000..cc94e061ea
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleTable.h
@@ -0,0 +1,178 @@
+/* -*- 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"
+#include "ia2AccessibleHypertext.h"
+#include "IUnknownImpl.h"
+
+namespace mozilla {
+namespace a11y {
+
+class TableAccessibleBase;
+
+class ia2AccessibleTable : public IAccessibleTable,
+ public IAccessibleTable2,
+ public ia2AccessibleHypertext {
+ public:
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+ IMPL_IUNKNOWN_REFCOUNTING_INHERITED(ia2AccessibleHypertext)
+
+ // 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:
+ using ia2AccessibleHypertext::ia2AccessibleHypertext;
+
+ private:
+ TableAccessibleBase* TableAcc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleTableCell.cpp b/accessible/windows/ia2/ia2AccessibleTableCell.cpp
new file mode 100644
index 0000000000..74b6c4233d
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleTableCell.cpp
@@ -0,0 +1,186 @@
+/* -*- 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 "AccessibleTable2_i.c"
+#include "AccessibleTableCell_i.c"
+
+#include "IUnknownImpl.h"
+#include "mozilla/a11y/Accessible.h"
+#include "mozilla/a11y/TableAccessibleBase.h"
+#include "mozilla/a11y/TableCellAccessibleBase.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+using namespace mozilla::a11y;
+
+TableCellAccessibleBase* ia2AccessibleTableCell::CellAcc() {
+ Accessible* acc = Acc();
+ return acc ? acc->AsTableCellBase() : nullptr;
+}
+
+// IUnknown
+IMPL_IUNKNOWN_QUERY_HEAD(ia2AccessibleTableCell)
+IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleTableCell)
+IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(ia2AccessibleHypertext)
+
+////////////////////////////////////////////////////////////////////////////////
+// IAccessibleTableCell
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_table(IUnknown** aTable) {
+ if (!aTable) return E_INVALIDARG;
+
+ *aTable = nullptr;
+ TableCellAccessibleBase* tableCell = CellAcc();
+ if (!tableCell) return CO_E_OBJNOTCONNECTED;
+
+ TableAccessibleBase* table = tableCell->Table();
+ if (!table) return E_FAIL;
+
+ Accessible* tableAcc = table->AsAccessible();
+ RefPtr<IAccessible> result = MsaaAccessible::GetFrom(tableAcc);
+ result.forget(aTable);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_columnExtent(long* aSpan) {
+ if (!aSpan) return E_INVALIDARG;
+
+ *aSpan = 0;
+ TableCellAccessibleBase* tableCell = CellAcc();
+ if (!tableCell) return CO_E_OBJNOTCONNECTED;
+
+ *aSpan = tableCell->ColExtent();
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_columnHeaderCells(IUnknown*** aCellAccessibles,
+ long* aNColumnHeaderCells) {
+ if (!aCellAccessibles || !aNColumnHeaderCells) return E_INVALIDARG;
+
+ *aCellAccessibles = nullptr;
+ *aNColumnHeaderCells = 0;
+ TableCellAccessibleBase* tableCell = CellAcc();
+ if (!tableCell) return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<Accessible*, 10> cells;
+ tableCell->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++) {
+ RefPtr<IAccessible> iaCell = MsaaAccessible::GetFrom(cells[i]);
+ iaCell.forget(&(*aCellAccessibles)[i]);
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_columnIndex(long* aColIdx) {
+ if (!aColIdx) return E_INVALIDARG;
+
+ *aColIdx = -1;
+ TableCellAccessibleBase* tableCell = CellAcc();
+ if (!tableCell) return CO_E_OBJNOTCONNECTED;
+
+ *aColIdx = tableCell->ColIdx();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_rowExtent(long* aSpan) {
+ if (!aSpan) return E_INVALIDARG;
+
+ *aSpan = 0;
+ TableCellAccessibleBase* tableCell = CellAcc();
+ if (!tableCell) return CO_E_OBJNOTCONNECTED;
+
+ *aSpan = tableCell->RowExtent();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_rowHeaderCells(IUnknown*** aCellAccessibles,
+ long* aNRowHeaderCells) {
+ if (!aCellAccessibles || !aNRowHeaderCells) return E_INVALIDARG;
+
+ *aCellAccessibles = nullptr;
+ *aNRowHeaderCells = 0;
+ TableCellAccessibleBase* tableCell = CellAcc();
+ if (!tableCell) return CO_E_OBJNOTCONNECTED;
+
+ AutoTArray<Accessible*, 10> cells;
+ tableCell->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++) {
+ RefPtr<IAccessible> iaCell = MsaaAccessible::GetFrom(cells[i]);
+ iaCell.forget(&(*aCellAccessibles)[i]);
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_rowIndex(long* aRowIdx) {
+ if (!aRowIdx) return E_INVALIDARG;
+
+ *aRowIdx = -1;
+ TableCellAccessibleBase* tableCell = CellAcc();
+ if (!tableCell) return CO_E_OBJNOTCONNECTED;
+
+ *aRowIdx = tableCell->RowIdx();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_rowColumnExtents(long* aRowIdx, long* aColIdx,
+ long* aRowExtents,
+ long* aColExtents,
+ boolean* aIsSelected) {
+ if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected)
+ return E_INVALIDARG;
+
+ *aRowIdx = *aColIdx = *aRowExtents = *aColExtents = 0;
+ *aIsSelected = false;
+ TableCellAccessibleBase* tableCell = CellAcc();
+ if (!tableCell) return CO_E_OBJNOTCONNECTED;
+
+ *aRowIdx = tableCell->RowIdx();
+ *aColIdx = tableCell->ColIdx();
+ *aRowExtents = tableCell->RowExtent();
+ *aColExtents = tableCell->ColExtent();
+ *aIsSelected = tableCell->Selected();
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleTableCell::get_isSelected(boolean* aIsSelected) {
+ if (!aIsSelected) return E_INVALIDARG;
+
+ *aIsSelected = false;
+ TableCellAccessibleBase* tableCell = CellAcc();
+ if (!tableCell) return CO_E_OBJNOTCONNECTED;
+
+ *aIsSelected = tableCell->Selected();
+ return S_OK;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleTableCell.h b/accessible/windows/ia2/ia2AccessibleTableCell.h
new file mode 100644
index 0000000000..b0cc00ce00
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleTableCell.h
@@ -0,0 +1,71 @@
+/* -*- 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"
+#include "ia2AccessibleHypertext.h"
+#include "IUnknownImpl.h"
+
+namespace mozilla {
+namespace a11y {
+class TableCellAccessibleBase;
+
+class ia2AccessibleTableCell : public IAccessibleTableCell,
+ public ia2AccessibleHypertext {
+ public:
+ // IUnknown
+ DECL_IUNKNOWN_INHERITED
+ IMPL_IUNKNOWN_REFCOUNTING_INHERITED(ia2AccessibleHypertext)
+
+ // 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:
+ using ia2AccessibleHypertext::ia2AccessibleHypertext;
+
+ private:
+ TableCellAccessibleBase* CellAcc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/ia2AccessibleText.cpp b/accessible/windows/ia2/ia2AccessibleText.cpp
new file mode 100644
index 0000000000..66b888bc63
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleText.cpp
@@ -0,0 +1,481 @@
+/* -*- 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 "ia2Accessible.h"
+#include "ia2AccessibleHypertext.h"
+#include "ia2AccessibleText.h"
+
+#include "AccessibleText_i.c"
+
+#include "HyperTextAccessibleWrap.h"
+#include "HyperTextAccessible-inl.h"
+#include "mozilla/ClearOnShutdown.h"
+
+using namespace mozilla::a11y;
+
+HyperTextAccessibleBase* ia2AccessibleText::sLastTextChangeAcc = nullptr;
+StaticAutoPtr<nsString> ia2AccessibleText::sLastTextChangeString;
+uint32_t ia2AccessibleText::sLastTextChangeStart = 0;
+uint32_t ia2AccessibleText::sLastTextChangeEnd = 0;
+bool ia2AccessibleText::sLastTextChangeWasInsert = false;
+
+HyperTextAccessibleBase* ia2AccessibleText::TextAcc() {
+ auto hyp = static_cast<ia2AccessibleHypertext*>(this);
+ Accessible* acc = hyp->Acc();
+ return acc ? acc->AsHyperTextBase() : nullptr;
+}
+
+std::pair<HyperTextAccessibleWrap*, HRESULT> ia2AccessibleText::LocalTextAcc() {
+ auto hyp = static_cast<ia2AccessibleHypertext*>(this);
+ Accessible* acc = hyp->Acc();
+ if (!acc) {
+ return {nullptr, CO_E_OBJNOTCONNECTED};
+ }
+ auto localAcc = static_cast<AccessibleWrap*>(acc->AsLocal());
+ if (!localAcc) {
+ return {nullptr, E_NOTIMPL};
+ }
+ return {static_cast<HyperTextAccessibleWrap*>(localAcc), S_OK};
+}
+
+// IAccessibleText
+
+STDMETHODIMP
+ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset) {
+ auto [textAcc, hr] = LocalTextAcc();
+ if (!textAcc) {
+ return hr;
+ }
+
+ return textAcc->AddToSelection(aStartOffset, aEndOffset) ? S_OK
+ : E_INVALIDARG;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_attributes(long aOffset, long* aStartOffset,
+ long* aEndOffset, BSTR* aTextAttributes) {
+ if (!aStartOffset || !aEndOffset || !aTextAttributes) return E_INVALIDARG;
+
+ *aStartOffset = 0;
+ *aEndOffset = 0;
+ *aTextAttributes = nullptr;
+
+ int32_t startOffset = 0, endOffset = 0;
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ RefPtr<AccAttributes> attributes =
+ textAcc->TextAttributes(true, aOffset, &startOffset, &endOffset);
+
+ HRESULT hr =
+ ia2Accessible::ConvertToIA2Attributes(attributes, aTextAttributes);
+ if (FAILED(hr)) return hr;
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_caretOffset(long* aOffset) {
+ if (!aOffset) return E_INVALIDARG;
+
+ *aOffset = -1;
+
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ *aOffset = textAcc->CaretOffset();
+
+ return *aOffset != -1 ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_characterExtents(long aOffset,
+ enum IA2CoordinateType aCoordType,
+ long* aX, long* aY, long* aWidth,
+ long* aHeight) {
+ 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;
+ LayoutDeviceIntRect rect;
+ auto textAcc = TextAcc();
+ if (!textAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ rect = textAcc->CharBounds(aOffset, geckoCoordType);
+
+ // Can't use GetRect() because of long vs. int32_t mismatch
+ *aX = rect.X();
+ *aY = rect.Y();
+ *aWidth = rect.Width();
+ *aHeight = rect.Height();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_nSelections(long* aNSelections) {
+ if (!aNSelections) return E_INVALIDARG;
+ *aNSelections = 0;
+
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ *aNSelections = textAcc->SelectionCount();
+
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_offsetAtPoint(long aX, long aY,
+ enum IA2CoordinateType aCoordType,
+ long* aOffset) {
+ if (!aOffset) return E_INVALIDARG;
+ *aOffset = 0;
+
+ uint32_t geckoCoordType =
+ (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE)
+ ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
+ : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ *aOffset = textAcc->OffsetAtPoint(aX, aY, geckoCoordType);
+
+ return *aOffset == -1 ? S_FALSE : S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_selection(long aSelectionIndex, long* aStartOffset,
+ long* aEndOffset) {
+ if (!aStartOffset || !aEndOffset) return E_INVALIDARG;
+ *aStartOffset = *aEndOffset = 0;
+
+ int32_t startOffset = 0, endOffset = 0;
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (!textAcc->SelectionBoundsAt(aSelectionIndex, &startOffset, &endOffset)) {
+ return E_INVALIDARG;
+ }
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR* aText) {
+ if (!aText) return E_INVALIDARG;
+
+ *aText = nullptr;
+
+ nsAutoString text;
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) {
+ 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;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_textBeforeOffset(long aOffset,
+ enum IA2TextBoundaryType aBoundaryType,
+ long* aStartOffset, long* aEndOffset,
+ BSTR* aText) {
+ if (!aStartOffset || !aEndOffset || !aText) return E_INVALIDARG;
+
+ *aStartOffset = *aEndOffset = 0;
+ *aText = nullptr;
+
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) {
+ 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;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_textAfterOffset(long aOffset,
+ enum IA2TextBoundaryType aBoundaryType,
+ long* aStartOffset, long* aEndOffset,
+ BSTR* aText) {
+ if (!aStartOffset || !aEndOffset || !aText) return E_INVALIDARG;
+
+ *aStartOffset = 0;
+ *aEndOffset = 0;
+ *aText = nullptr;
+
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) {
+ 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;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_textAtOffset(long aOffset,
+ enum IA2TextBoundaryType aBoundaryType,
+ long* aStartOffset, long* aEndOffset,
+ BSTR* aText) {
+ if (!aStartOffset || !aEndOffset || !aText) return E_INVALIDARG;
+
+ *aStartOffset = *aEndOffset = 0;
+ *aText = nullptr;
+
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) 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;
+}
+
+STDMETHODIMP
+ia2AccessibleText::removeSelection(long aSelectionIndex) {
+ auto [textAcc, hr] = LocalTextAcc();
+ if (!textAcc) {
+ return hr;
+ }
+
+ return textAcc->RemoveFromSelection(aSelectionIndex) ? S_OK : E_INVALIDARG;
+}
+
+STDMETHODIMP
+ia2AccessibleText::setCaretOffset(long aOffset) {
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
+
+ textAcc->SetCaretOffset(aOffset);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleText::setSelection(long aSelectionIndex, long aStartOffset,
+ long aEndOffset) {
+ auto [textAcc, hr] = LocalTextAcc();
+ if (!textAcc) {
+ return hr;
+ }
+
+ return textAcc->SetSelectionBoundsAt(aSelectionIndex, aStartOffset,
+ aEndOffset)
+ ? S_OK
+ : E_INVALIDARG;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_nCharacters(long* aNCharacters) {
+ if (!aNCharacters) return E_INVALIDARG;
+ *aNCharacters = 0;
+
+ HyperTextAccessibleBase* textAcc = TextAcc();
+ if (!textAcc) return CO_E_OBJNOTCONNECTED;
+
+ *aNCharacters = textAcc->CharacterCount();
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex,
+ enum IA2ScrollType aScrollType) {
+ auto [textAcc, hr] = LocalTextAcc();
+ if (!textAcc) {
+ return hr;
+ }
+
+ if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) return E_INVALIDARG;
+
+ textAcc->ScrollSubstringTo(aStartIndex, aEndIndex, aScrollType);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleText::scrollSubstringToPoint(long aStartIndex, long aEndIndex,
+ enum IA2CoordinateType aCoordType,
+ long aX, long aY) {
+ uint32_t geckoCoordType =
+ (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE)
+ ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
+ : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+
+ auto [textAcc, hr] = LocalTextAcc();
+ if (!textAcc) {
+ return hr;
+ }
+
+ if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) return E_INVALIDARG;
+
+ textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex, geckoCoordType, aX,
+ aY);
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_newText(IA2TextSegment* aNewText) {
+ return GetModifiedText(true, aNewText);
+}
+
+STDMETHODIMP
+ia2AccessibleText::get_oldText(IA2TextSegment* aOldText) {
+ return GetModifiedText(false, aOldText);
+}
+
+// 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 != TextAcc()) 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_PARAGRAPH:
+ return nsIAccessibleText::BOUNDARY_PARAGRAPH;
+ // case IA2_TEXT_BOUNDARY_SENTENCE:
+ // XXX: not implemented
+ default:
+ return -1;
+ }
+}
+
+void ia2AccessibleText::InitTextChangeData() {
+ ClearOnShutdown(&sLastTextChangeString);
+}
+
+void ia2AccessibleText::UpdateTextChangeData(HyperTextAccessibleBase* aAcc,
+ bool aInsert,
+ const nsAString& 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 0000000000..8b9bab04b3
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleText.h
@@ -0,0 +1,255 @@
+/* -*- 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 <utility>
+#include "AccessibleText.h"
+#include "nsIAccessibleText.h"
+
+namespace mozilla {
+template <class T>
+class StaticAutoPtr;
+template <class T>
+class StaticRefPtr;
+
+namespace a11y {
+class HyperTextAccessibleBase;
+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(HyperTextAccessibleBase* aAcc, bool aInsert,
+ const nsAString& aStr, int32_t aStart,
+ uint32_t aLen);
+
+ protected:
+ // This can't be a RefPtr because RemoteAccessibles aren't ref counted. It
+ // can't be an id because this is global and ids are only unique within the
+ // document. Since this is only used for comparison, we use a raw pointer.
+ // This should *never* be dereferenced, only used for comparison!
+ static HyperTextAccessibleBase* 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);
+ HyperTextAccessibleBase* TextAcc();
+
+ /**
+ * This can return null for two reasons. The HRESULT indicates the reason:
+ * CO_E_OBJNOTCONNECTED: The Accessible is dead.
+ * E_NOTIMPL: It isn't a LocalAccessible (so we can't support the method
+ * being called yet).
+ */
+ std::pair<HyperTextAccessibleWrap*, HRESULT> LocalTextAcc();
+};
+
+} // 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 0000000000..ed8b7a4de2
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleValue.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 "ia2AccessibleValue.h"
+
+#include "AccessibleValue_i.c"
+
+#include "AccessibleWrap.h"
+#include "LocalAccessible-inl.h"
+#include "IUnknownImpl.h"
+
+#include "mozilla/FloatingPoint.h"
+
+using namespace mozilla::a11y;
+
+AccessibleWrap* ia2AccessibleValue::LocalAcc() {
+ return static_cast<MsaaAccessible*>(this)->LocalAcc();
+}
+
+Accessible* ia2AccessibleValue::Acc() {
+ return static_cast<MsaaAccessible*>(this)->Acc();
+}
+
+// IUnknown
+
+STDMETHODIMP
+ia2AccessibleValue::QueryInterface(REFIID iid, void** ppv) {
+ if (!ppv) return E_INVALIDARG;
+
+ *ppv = nullptr;
+
+ if (IID_IAccessibleValue == iid) {
+ Accessible* valueAcc = Acc();
+ if (valueAcc && valueAcc->HasNumericValue()) {
+ RefPtr<IAccessibleValue> result = this;
+ result.forget(ppv);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+ return E_NOINTERFACE;
+}
+
+// IAccessibleValue
+
+STDMETHODIMP
+ia2AccessibleValue::get_currentValue(VARIANT* aCurrentValue) {
+ if (!aCurrentValue) return E_INVALIDARG;
+
+ VariantInit(aCurrentValue);
+
+ Accessible* valueAcc = Acc();
+ if (!valueAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ double currentValue;
+
+ currentValue = valueAcc->CurValue();
+
+ if (IsNaN(currentValue)) return S_FALSE;
+
+ aCurrentValue->vt = VT_R8;
+ aCurrentValue->dblVal = currentValue;
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleValue::setCurrentValue(VARIANT aValue) {
+ if (aValue.vt != VT_R8) return E_INVALIDARG;
+
+ AccessibleWrap* valueAcc = LocalAcc();
+ if (!valueAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ return valueAcc->SetCurValue(aValue.dblVal) ? S_OK : E_FAIL;
+}
+
+STDMETHODIMP
+ia2AccessibleValue::get_maximumValue(VARIANT* aMaximumValue) {
+ if (!aMaximumValue) return E_INVALIDARG;
+
+ VariantInit(aMaximumValue);
+
+ Accessible* valueAcc = Acc();
+ if (!valueAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ double maximumValue;
+
+ maximumValue = valueAcc->MaxValue();
+
+ if (IsNaN(maximumValue)) return S_FALSE;
+
+ aMaximumValue->vt = VT_R8;
+ aMaximumValue->dblVal = maximumValue;
+ return S_OK;
+}
+
+STDMETHODIMP
+ia2AccessibleValue::get_minimumValue(VARIANT* aMinimumValue) {
+ if (!aMinimumValue) return E_INVALIDARG;
+
+ VariantInit(aMinimumValue);
+
+ Accessible* valueAcc = Acc();
+ if (!valueAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ double minimumValue;
+
+ minimumValue = valueAcc->MinValue();
+
+ if (IsNaN(minimumValue)) return S_FALSE;
+
+ aMinimumValue->vt = VT_R8;
+ aMinimumValue->dblVal = minimumValue;
+ return S_OK;
+}
diff --git a/accessible/windows/ia2/ia2AccessibleValue.h b/accessible/windows/ia2/ia2AccessibleValue.h
new file mode 100644
index 0000000000..368dbef244
--- /dev/null
+++ b/accessible/windows/ia2/ia2AccessibleValue.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_VALUE_H
+#define _ACCESSIBLE_VALUE_H
+
+#include "AccessibleValue.h"
+
+namespace mozilla {
+namespace a11y {
+class AccessibleWrap;
+
+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);
+
+ private:
+ Accessible* Acc();
+ AccessibleWrap* LocalAcc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/ia2/moz.build b/accessible/windows/ia2/moz.build
new file mode 100644
index 0000000000..8c6ffdc7e9
--- /dev/null
+++ b/accessible/windows/ia2/moz.build
@@ -0,0 +1,61 @@
+# -*- 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",
+ "ia2AccessibleApplication.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["CC_TYPE"] == "clang-cl":
+ CXXFLAGS += ["-Wno-extra-tokens"]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+REQUIRES_UNIFIED_BUILD = True