diff options
Diffstat (limited to 'accessible/windows/ia2')
25 files changed, 3835 insertions, 0 deletions
diff --git a/accessible/windows/ia2/ia2Accessible.cpp b/accessible/windows/ia2/ia2Accessible.cpp new file mode 100644 index 0000000000..b042e41913 --- /dev/null +++ b/accessible/windows/ia2/ia2Accessible.cpp @@ -0,0 +1,632 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AccessibleWrap.h" + +#include "Accessible2_i.c" +#include "Accessible2_2_i.c" +#include "Accessible2_3_i.c" +#include "AccessibleRole.h" +#include "AccessibleStates.h" + +#include "Compatibility.h" +#include "ia2AccessibleRelation.h" +#include "IUnknownImpl.h" +#include "nsCoreUtils.h" +#include "nsIAccessibleTypes.h" +#include "mozilla/a11y/PDocAccessible.h" +#include "Relation.h" +#include "TextRange-inl.h" +#include "nsAccessibilityService.h" + +#include "mozilla/PresShell.h" +#include "nsIPersistentProperties2.h" +#include "nsISimpleEnumerator.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +template <typename String> +static void EscapeAttributeChars(String& aStr); + +//////////////////////////////////////////////////////////////////////////////// +// ia2Accessible +//////////////////////////////////////////////////////////////////////////////// + +STDMETHODIMP +ia2Accessible::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + // 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; +} + +//////////////////////////////////////////////////////////////////////////////// +// IAccessible2 + +STDMETHODIMP +ia2Accessible::get_nRelations(long* aNRelations) { + if (!aNRelations) return E_INVALIDARG; + *aNRelations = 0; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + MOZ_ASSERT(!acc->IsProxy()); + + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { + if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; + + Relation rel = acc->RelationByType(sRelationTypePairs[idx].first); + if (rel.Next()) (*aNRelations)++; + } + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_relation(long aRelationIndex, + IAccessibleRelation** aRelation) { + if (!aRelation || aRelationIndex < 0) return E_INVALIDARG; + *aRelation = nullptr; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + MOZ_ASSERT(!acc->IsProxy()); + + long relIdx = 0; + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { + if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; + + RelationType relationType = sRelationTypePairs[idx].first; + Relation rel = acc->RelationByType(relationType); + RefPtr<ia2AccessibleRelation> ia2Relation = + new ia2AccessibleRelation(relationType, &rel); + if (ia2Relation->HasTargets()) { + if (relIdx == aRelationIndex) { + acc->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; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + MOZ_ASSERT(!acc->IsProxy()); + + for (uint32_t idx = 0; + idx < ArrayLength(sRelationTypePairs) && *aNRelations < aMaxRelations; + idx++) { + if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; + + RelationType relationType = sRelationTypePairs[idx].first; + Relation rel = acc->RelationByType(relationType); + RefPtr<ia2AccessibleRelation> ia2Rel = + new ia2AccessibleRelation(relationType, &rel); + if (ia2Rel->HasTargets()) { + acc->AssociateCOMObjectForDisconnection(ia2Rel); + ia2Rel.forget(aRelation + (*aNRelations)); + (*aNRelations)++; + } + } + return S_OK; +} + +STDMETHODIMP +ia2Accessible::role(long* aRole) { + if (!aRole) return E_INVALIDARG; + *aRole = 0; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + +#define ROLE(_geckoRole, stringRole, atkRole, macRole, macSubrole, msaaRole, \ + ia2Role, androidClass, nameRule) \ + case roles::_geckoRole: \ + *aRole = ia2Role; \ + break; + + a11y::role geckoRole; + MOZ_ASSERT(!acc->IsProxy()); + geckoRole = acc->Role(); + switch (geckoRole) { +#include "RoleMap.h" + default: + MOZ_CRASH("Unknown role."); + } + +#undef ROLE + + // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call + // the IA2 role a ROLE_OUTLINEITEM. + MOZ_ASSERT(!acc->IsProxy()); + if (geckoRole == roles::ROW) { + Accessible* xpParent = acc->Parent(); + if (xpParent && xpParent->Role() == roles::TREE_TABLE) + *aRole = ROLE_SYSTEM_OUTLINEITEM; + } + + return S_OK; +} + +// XXX Use MOZ_CAN_RUN_SCRIPT_BOUNDARY for now due to bug 1543294. +MOZ_CAN_RUN_SCRIPT_BOUNDARY STDMETHODIMP +ia2Accessible::scrollTo(enum IA2ScrollType aScrollType) { + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + MOZ_ASSERT(!acc->IsProxy()); + RefPtr<PresShell> presShell = acc->Document()->PresShellPtr(); + nsCOMPtr<nsIContent> content = acc->GetContent(); + nsCoreUtils::ScrollTo(presShell, content, aScrollType); + + return S_OK; +} + +STDMETHODIMP +ia2Accessible::scrollToPoint(enum IA2CoordinateType aCoordType, long aX, + long aY) { + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + uint32_t geckoCoordType = + (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) + ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE + : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + + MOZ_ASSERT(!acc->IsProxy()); + acc->ScrollToPoint(geckoCoordType, aX, aY); + + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_groupPosition(long* aGroupLevel, long* aSimilarItemsInGroup, + long* aPositionInGroup) { + if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup) + return E_INVALIDARG; + + *aGroupLevel = 0; + *aSimilarItemsInGroup = 0; + *aPositionInGroup = 0; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + GroupPos groupPos = acc->GroupPosition(); + + // Group information for accessibles having level only (like html headings + // elements) isn't exposed by this method. AT should look for 'level' object + // attribute. + if (!groupPos.setSize && !groupPos.posInSet) return S_FALSE; + + *aGroupLevel = groupPos.level; + *aSimilarItemsInGroup = groupPos.setSize; + *aPositionInGroup = groupPos.posInSet; + + return S_OK; +} + +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. + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) { + *aStates = IA2_STATE_DEFUNCT; + return S_OK; + } + + uint64_t state; + MOZ_ASSERT(!acc->IsProxy()); + state = acc->State(); + + if (state & states::INVALID) *aStates |= IA2_STATE_INVALID_ENTRY; + if (state & states::REQUIRED) *aStates |= IA2_STATE_REQUIRED; + + // The following IA2 states are not supported by Gecko + // IA2_STATE_ARMED + // IA2_STATE_MANAGES_DESCENDANTS + // IA2_STATE_ICONIFIED + // IA2_STATE_INVALID // This is not a state, it is the absence of a state + + if (state & states::ACTIVE) *aStates |= IA2_STATE_ACTIVE; + if (state & states::DEFUNCT) *aStates |= IA2_STATE_DEFUNCT; + if (state & states::EDITABLE) *aStates |= IA2_STATE_EDITABLE; + if (state & states::HORIZONTAL) *aStates |= IA2_STATE_HORIZONTAL; + if (state & states::MODAL) *aStates |= IA2_STATE_MODAL; + if (state & states::MULTI_LINE) *aStates |= IA2_STATE_MULTI_LINE; + if (state & states::OPAQUE1) *aStates |= IA2_STATE_OPAQUE; + if (state & states::SELECTABLE_TEXT) *aStates |= IA2_STATE_SELECTABLE_TEXT; + if (state & states::SINGLE_LINE) *aStates |= IA2_STATE_SINGLE_LINE; + if (state & states::STALE) *aStates |= IA2_STATE_STALE; + if (state & states::SUPPORTS_AUTOCOMPLETION) + *aStates |= IA2_STATE_SUPPORTS_AUTOCOMPLETION; + if (state & states::TRANSIENT) *aStates |= IA2_STATE_TRANSIENT; + if (state & states::VERTICAL) *aStates |= IA2_STATE_VERTICAL; + if (state & states::CHECKED) *aStates |= IA2_STATE_CHECKABLE; + if (state & states::PINNED) *aStates |= IA2_STATE_PINNED; + + return S_OK; +} + +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; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + *aUniqueID = AccessibleWrap::GetChildIDFor(acc); + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_windowHandle(HWND* aWindowHandle) { + if (!aWindowHandle) return E_INVALIDARG; + *aWindowHandle = 0; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + *aWindowHandle = AccessibleWrap::GetHWNDFor(acc); + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_indexInParent(long* aIndexInParent) { + if (!aIndexInParent) return E_INVALIDARG; + *aIndexInParent = -1; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + MOZ_ASSERT(!acc->IsProxy()); + *aIndexInParent = acc->IndexInParent(); + + if (*aIndexInParent == -1) return S_FALSE; + + return S_OK; +} + +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. + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + nsAutoString lang; + acc->Language(lang); + + // If primary code consists from two letters then expose it as language. + int32_t offset = lang.FindChar('-', 0); + if (offset == -1) { + if (lang.Length() == 2) { + aLocale->language = ::SysAllocString(lang.get()); + return S_OK; + } + } else if (offset == 2) { + aLocale->language = ::SysAllocStringLen(lang.get(), 2); + + // If the first subcode consists from two letters then expose it as + // country. + offset = lang.FindChar('-', 3); + if (offset == -1) { + if (lang.Length() == 5) { + aLocale->country = ::SysAllocString(lang.get() + 3); + return S_OK; + } + } else if (offset == 5) { + aLocale->country = ::SysAllocStringLen(lang.get() + 3, 2); + } + } + + // Expose as a string if primary code or subcode cannot point to language or + // country abbreviations or if there are more than one subcode. + aLocale->variant = ::SysAllocString(lang.get()); + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_attributes(BSTR* aAttributes) { + if (!aAttributes) return E_INVALIDARG; + *aAttributes = nullptr; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + // The format is name:value;name:value; with \ for escaping these + // characters ":;=,\". + if (!acc->IsProxy()) { + nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes(); + return ConvertToIA2Attributes(attributes, aAttributes); + } + + MOZ_ASSERT(!acc->IsProxy()); + return E_UNEXPECTED; +} + +//////////////////////////////////////////////////////////////////////////////// +// 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; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + int32_t caretOffset = -1; + Accessible* accWithCaret = SelectionMgr()->AccessibleWithCaret(&caretOffset); + if (!accWithCaret || acc->Document() != accWithCaret->Document()) + return S_FALSE; + + Accessible* child = accWithCaret; + while (!child->IsDoc() && child != acc) child = child->Parent(); + + if (child != acc) return S_FALSE; + + *aAccessible = + static_cast<IAccessible2*>(static_cast<AccessibleWrap*>(accWithCaret)); + (*aAccessible)->AddRef(); + *aCaretOffset = caretOffset; + return S_OK; +} + +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; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + nsTArray<Accessible*> targets; + MOZ_ASSERT(!acc->IsProxy()); + Relation rel = acc->RelationByType(*relationType); + Accessible* target = nullptr; + while ( + (target = rel.Next()) && + (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++) { + AccessibleWrap* target = static_cast<AccessibleWrap*>(targets[i]); + (*aTargets)[i] = static_cast<IAccessible2*>(target); + (*aTargets)[i]->AddRef(); + } + + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_selectionRanges(IA2Range** aRanges, long* aNRanges) { + if (!aRanges || !aNRanges) return E_INVALIDARG; + + *aNRanges = 0; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + AutoTArray<TextRange, 1> ranges; + acc->Document()->SelectionRanges(&ranges); + 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++) { + AccessibleWrap* anchor = + static_cast<AccessibleWrap*>(ranges[idx].StartContainer()); + (*aRanges)[idx].anchor = static_cast<IAccessible2*>(anchor); + anchor->AddRef(); + + (*aRanges)[idx].anchorOffset = ranges[idx].StartOffset(); + + AccessibleWrap* active = + static_cast<AccessibleWrap*>(ranges[idx].EndContainer()); + (*aRanges)[idx].active = static_cast<IAccessible2*>(active); + active->AddRef(); + + (*aRanges)[idx].activeOffset = ranges[idx].EndOffset(); + } + + return S_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// Helpers + +template <typename String> +static inline void EscapeAttributeChars(String& aStr) { + int32_t offset = 0; + static const char kCharsToEscape[] = ":;=,\\"; + while ((offset = aStr.FindCharInSet(kCharsToEscape, offset)) != kNotFound) { + aStr.Insert('\\', offset); + offset += 2; + } +} + +HRESULT +ia2Accessible::ConvertToIA2Attributes(nsTArray<Attribute>* aAttributes, + BSTR* aIA2Attributes) { + nsString attrStr; + size_t attrCount = aAttributes->Length(); + for (size_t i = 0; i < attrCount; i++) { + EscapeAttributeChars(aAttributes->ElementAt(i).Name()); + EscapeAttributeChars(aAttributes->ElementAt(i).Value()); + AppendUTF8toUTF16(aAttributes->ElementAt(i).Name(), attrStr); + attrStr.Append(':'); + attrStr.Append(aAttributes->ElementAt(i).Value()); + attrStr.Append(';'); + } + + if (attrStr.IsEmpty()) return S_FALSE; + + *aIA2Attributes = ::SysAllocStringLen(attrStr.get(), attrStr.Length()); + return *aIA2Attributes ? S_OK : E_OUTOFMEMORY; +} + +HRESULT +ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes, + BSTR* aIA2Attributes) { + *aIA2Attributes = nullptr; + + // The format is name:value;name:value; with \ for escaping these + // characters ":;=,\". + + if (!aAttributes) return S_FALSE; + + nsCOMPtr<nsISimpleEnumerator> propEnum; + aAttributes->Enumerate(getter_AddRefs(propEnum)); + if (!propEnum) return E_FAIL; + + nsAutoString strAttrs; + + bool hasMore = false; + while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr<nsISupports> propSupports; + propEnum->GetNext(getter_AddRefs(propSupports)); + + nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(propSupports)); + if (!propElem) return E_FAIL; + + nsAutoCString name; + if (NS_FAILED(propElem->GetKey(name))) return E_FAIL; + + EscapeAttributeChars(name); + + nsAutoString value; + if (NS_FAILED(propElem->GetValue(value))) return E_FAIL; + + EscapeAttributeChars(value); + + AppendUTF8toUTF16(name, strAttrs); + strAttrs.Append(':'); + strAttrs.Append(value); + strAttrs.Append(';'); + } + + if (strAttrs.IsEmpty()) return S_FALSE; + + *aIA2Attributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length()); + return *aIA2Attributes ? S_OK : E_OUTOFMEMORY; +} diff --git a/accessible/windows/ia2/ia2Accessible.h b/accessible/windows/ia2/ia2Accessible.h new file mode 100644 index 0000000000..3a8afe46b4 --- /dev/null +++ b/accessible/windows/ia2/ia2Accessible.h @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_ia2Accessible_h_ +#define mozilla_a11y_ia2Accessible_h_ + +#include "nsISupports.h" + +#include "Accessible2_3.h" + +namespace mozilla { +namespace a11y { +class Attribute; + +class ia2Accessible : public IAccessible2_3 { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessible2 + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nRelations( + /* [retval][out] */ long* nRelations); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relation( + /* [in] */ long relationIndex, + /* [retval][out] */ IAccessibleRelation** relation); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relations( + /* [in] */ long maxRelations, + /* [length_is][size_is][out] */ IAccessibleRelation** relation, + /* [retval][out] */ long* nRelations); + + virtual HRESULT STDMETHODCALLTYPE role( + /* [retval][out] */ long* role); + + virtual HRESULT STDMETHODCALLTYPE scrollTo( + /* [in] */ enum IA2ScrollType scrollType); + + virtual HRESULT STDMETHODCALLTYPE scrollToPoint( + /* [in] */ enum IA2CoordinateType coordinateType, + /* [in] */ long x, + /* [in] */ long y); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_groupPosition( + /* [out] */ long* groupLevel, + /* [out] */ long* similarItemsInGroup, + /* [retval][out] */ long* positionInGroup); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_states( + /* [retval][out] */ AccessibleStates* states); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_extendedRole( + /* [retval][out] */ BSTR* extendedRole); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedExtendedRole( + /* [retval][out] */ BSTR* localizedExtendedRole); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nExtendedStates( + /* [retval][out] */ long* nExtendedStates); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_extendedStates( + /* [in] */ long maxExtendedStates, + /* [length_is][length_is][size_is][size_is][out] */ BSTR** extendedStates, + /* [retval][out] */ long* nExtendedStates); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedExtendedStates( + /* [in] */ long maxLocalizedExtendedStates, + /* [length_is][length_is][size_is][size_is][out] */ + BSTR** localizedExtendedStates, + /* [retval][out] */ long* nLocalizedExtendedStates); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_uniqueID( + /* [retval][out] */ long* uniqueID); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_windowHandle( + /* [retval][out] */ HWND* windowHandle); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_indexInParent( + /* [retval][out] */ long* indexInParent); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_locale( + /* [retval][out] */ IA2Locale* locale); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_attributes( + /* [retval][out] */ BSTR* attributes); + + // IAccessible2_2 + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_attribute( + /* [in] */ BSTR name, + /* [out, retval] */ VARIANT* attribute); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_accessibleWithCaret( + /* [out] */ IUnknown** accessible, + /* [out, retval] */ long* caretOffset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relationTargetsOfType( + /* [in] */ BSTR type, + /* [in] */ long maxTargets, + /* [out, size_is(,*nTargets)] */ IUnknown*** targets, + /* [out, retval] */ long* nTargets); + + // IAccessible2_3 + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectionRanges( + /* [out, size_is(,*nRanges)] */ IA2Range** ranges, + /* [out, retval] */ long* nRanges); + + // Helper method + static HRESULT ConvertToIA2Attributes(nsIPersistentProperties* aAttributes, + BSTR* aIA2Attributes); + static HRESULT ConvertToIA2Attributes(nsTArray<Attribute>* aAttributes, + BSTR* aIA2Attributes); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleAction.cpp b/accessible/windows/ia2/ia2AccessibleAction.cpp new file mode 100644 index 0000000000..4671a48256 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleAction.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 "ia2AccessibleAction.h" + +#include "AccessibleAction_i.c" + +#include "AccessibleWrap.h" +#include "IUnknownImpl.h" + +using namespace mozilla::a11y; + +// IUnknown + +STDMETHODIMP +ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleAction == iid && + !static_cast<AccessibleWrap*>(this)->IsProxy()) { + *ppv = static_cast<IAccessibleAction*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +// IAccessibleAction + +STDMETHODIMP +ia2AccessibleAction::nActions(long* aActionCount) { + if (!aActionCount) return E_INVALIDARG; + + *aActionCount = 0; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + *aActionCount = acc->ActionCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleAction::doAction(long aActionIndex) { + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + uint8_t index = static_cast<uint8_t>(aActionIndex); + return acc->DoAction(index) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP +ia2AccessibleAction::get_description(long aActionIndex, BSTR* aDescription) { + if (!aDescription) return E_INVALIDARG; + *aDescription = nullptr; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + nsAutoString description; + uint8_t index = static_cast<uint8_t>(aActionIndex); + acc->ActionDescriptionAt(index, description); + if (description.IsEmpty()) return S_FALSE; + + *aDescription = ::SysAllocStringLen(description.get(), description.Length()); + return *aDescription ? S_OK : E_OUTOFMEMORY; +} + +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; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + // Expose keyboard shortcut if it's not exposed via MSAA keyboard shortcut. + KeyBinding keyBinding = acc->AccessKey(); + if (keyBinding.IsEmpty()) return S_FALSE; + + keyBinding = acc->KeyboardShortcut(); + if (keyBinding.IsEmpty()) return S_FALSE; + + nsAutoString keyStr; + keyBinding.ToString(keyStr); + + *aKeyBinding = static_cast<BSTR*>(::CoTaskMemAlloc(sizeof(BSTR*))); + if (!*aKeyBinding) return E_OUTOFMEMORY; + + *(aKeyBinding[0]) = ::SysAllocStringLen(keyStr.get(), keyStr.Length()); + if (!*(aKeyBinding[0])) { + ::CoTaskMemFree(*aKeyBinding); + return E_OUTOFMEMORY; + } + + *aNumBinding = 1; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleAction::get_name(long aActionIndex, BSTR* aName) { + if (!aName) return E_INVALIDARG; + + *aName = nullptr; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + nsAutoString name; + uint8_t index = static_cast<uint8_t>(aActionIndex); + acc->ActionNameAt(index, name); + if (name.IsEmpty()) return E_INVALIDARG; + + *aName = ::SysAllocStringLen(name.get(), name.Length()); + return *aName ? S_OK : E_OUTOFMEMORY; +} + +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..e85c345844 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleAction.h @@ -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/. */ + +#ifndef _ACCESSIBLE_ACTION_H +#define _ACCESSIBLE_ACTION_H + +#include "nsISupports.h" + +#include "AccessibleAction.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleAction : public IAccessibleAction { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleAction + virtual HRESULT STDMETHODCALLTYPE nActions( + /* [retval][out] */ long* nActions); + + virtual HRESULT STDMETHODCALLTYPE doAction( + /* [in] */ long actionIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_description( + /* [in] */ long actionIndex, + /* [retval][out] */ BSTR* description); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_keyBinding( + /* [in] */ long actionIndex, + /* [in] */ long nMaxBinding, + /* [length_is][length_is][size_is][size_is][out] */ BSTR** keyBinding, + /* [retval][out] */ long* nBinding); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_name( + /* [in] */ long actionIndex, + /* [retval][out] */ BSTR* name); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedName( + /* [in] */ long actionIndex, + /* [retval][out] */ BSTR* localizedName); +}; + +} // namespace a11y +} // namespace mozilla + +#define FORWARD_IACCESSIBLEACTION(Class) \ + virtual HRESULT STDMETHODCALLTYPE nActions(long* nActions) { \ + return Class::nActions(nActions); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE doAction(long actionIndex) { \ + return Class::doAction(actionIndex); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_description(long actionIndex, \ + BSTR* description) { \ + return Class::get_description(actionIndex, description); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_keyBinding( \ + long actionIndex, long nMaxBinding, BSTR** keyBinding, long* nBinding) { \ + return Class::get_keyBinding(actionIndex, nMaxBinding, keyBinding, \ + nBinding); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_name(long actionIndex, BSTR* name) { \ + return Class::get_name(actionIndex, name); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_localizedName(long actionIndex, \ + BSTR* localizedName) { \ + return Class::get_localizedName(actionIndex, localizedName); \ + } + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleComponent.cpp b/accessible/windows/ia2/ia2AccessibleComponent.cpp new file mode 100644 index 0000000000..9e6996cc12 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleComponent.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleComponent.h" + +#include "AccessibleComponent_i.c" + +#include "AccessibleWrap.h" +#include "States.h" +#include "IUnknownImpl.h" + +#include "nsIFrame.h" + +using namespace mozilla::a11y; + +// IUnknown + +STDMETHODIMP +ia2AccessibleComponent::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleComponent == iid) { + *ppv = static_cast<IAccessibleComponent*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +// IAccessibleComponent + +STDMETHODIMP +ia2AccessibleComponent::get_locationInParent(long* aX, long* aY) { + if (!aX || !aY) return E_INVALIDARG; + + *aX = 0; + *aY = 0; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + // If the object is not on any screen the returned position is (0,0). + uint64_t state = acc->State(); + if (state & states::INVISIBLE) return S_OK; + + nsIntRect rect = acc->Bounds(); + + // The coordinates of the returned position are relative to this object's + // parent or relative to the screen on which this object is rendered if it + // has no parent. + if (!acc->Parent()) { + *aX = rect.X(); + *aY = rect.Y(); + return S_OK; + } + + // The coordinates of the bounding box are given relative to the parent's + // coordinate system. + nsIntRect parentRect = acc->Parent()->Bounds(); + *aX = rect.X() - parentRect.X(); + *aY = rect.Y() - parentRect.Y(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleComponent::get_foreground(IA2Color* aForeground) { + if (!aForeground) return E_INVALIDARG; + + *aForeground = 0; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + nsIFrame* frame = acc->GetFrame(); + if (frame) *aForeground = frame->StyleText()->mColor.ToColor(); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleComponent::get_background(IA2Color* aBackground) { + if (!aBackground) return E_INVALIDARG; + + *aBackground = 0; + + AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + nsIFrame* frame = acc->GetFrame(); + if (frame) { + *aBackground = frame->StyleBackground()->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..54e87d1963 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleComponent.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef IA2_ACCESSIBLE_COMPONENT_H_ +#define IA2_ACCESSIBLE_COMPONENT_H_ + +#include "AccessibleComponent.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleComponent : public IAccessibleComponent { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleComponent + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_locationInParent( + /* [out] */ long* x, + /* [retval][out] */ long* y); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_foreground( + /* [retval][out] */ IA2Color* foreground); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_background( + /* [retval][out] */ IA2Color* background); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleEditableText.cpp b/accessible/windows/ia2/ia2AccessibleEditableText.cpp new file mode 100644 index 0000000000..06c1dc1530 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleEditableText.cpp @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleEditableText.h" + +#include "AccessibleEditableText_i.c" +#include "HyperTextAccessible-inl.h" +#include "HyperTextAccessibleWrap.h" +#include "ProxyWrappers.h" + +#include "nsCOMPtr.h" +#include "nsString.h" + +using namespace mozilla::a11y; + +// IAccessibleEditableText + +STDMETHODIMP +ia2AccessibleEditableText::copyText(long aStartOffset, long aEndOffset) { + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG; + + textAcc->CopyText(aStartOffset, aEndOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::deleteText(long aStartOffset, long aEndOffset) { + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG; + + textAcc->DeleteText(aStartOffset, aEndOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::insertText(long aOffset, BSTR* aText) { + uint32_t length = ::SysStringLen(*aText); + nsAutoString text(*aText, length); + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + textAcc->InsertText(text, aOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::cutText(long aStartOffset, long aEndOffset) { + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG; + + textAcc->CutText(aStartOffset, aEndOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::pasteText(long aOffset) { + MOZ_ASSERT(!HyperTextProxyFor(this)); + + RefPtr<HyperTextAccessible> textAcc = + static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + textAcc->PasteText(aOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::replaceText(long aStartOffset, long aEndOffset, + BSTR* aText) { + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG; + + textAcc->DeleteText(aStartOffset, aEndOffset); + + uint32_t length = ::SysStringLen(*aText); + nsAutoString text(*aText, length); + textAcc->InsertText(text, aStartOffset); + + return S_OK; +} + +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..7c6470773d --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleEditableText.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_EDITABLETEXT_H +#define _ACCESSIBLE_EDITABLETEXT_H + +#include "nsISupports.h" + +#include "AccessibleEditableText.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleEditableText : public IAccessibleEditableText { + public: + // IAccessibleEditableText + virtual HRESULT STDMETHODCALLTYPE copyText( + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + virtual HRESULT STDMETHODCALLTYPE deleteText( + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + virtual HRESULT STDMETHODCALLTYPE insertText( + /* [in] */ long offset, + /* [in] */ BSTR* text); + + virtual HRESULT STDMETHODCALLTYPE cutText( + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + 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); +}; + +} // 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..2943b3e530 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp @@ -0,0 +1,162 @@ +/* -*- 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; + +// IUnknown + +STDMETHODIMP +ia2AccessibleHyperlink::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleHyperlink == iid) { + auto accWrap = static_cast<AccessibleWrap*>(this); + if (accWrap->IsProxy() + ? !(accWrap->ProxyInterfaces() & Interfaces::HYPERLINK) + : !accWrap->IsLink()) + return E_NOINTERFACE; + + *ppv = static_cast<IAccessibleHyperlink*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return ia2AccessibleAction::QueryInterface(iid, ppv); +} + +// IAccessibleHyperlink + +STDMETHODIMP +ia2AccessibleHyperlink::get_anchor(long aIndex, VARIANT* aAnchor) { + if (!aAnchor) return E_INVALIDARG; + + VariantInit(aAnchor); + + Accessible* thisObj = static_cast<AccessibleWrap*>(this); + MOZ_ASSERT(!thisObj->IsProxy()); + + if (thisObj->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount())) + return E_INVALIDARG; + + if (!thisObj->IsLink()) return S_FALSE; + + AccessibleWrap* anchor = + static_cast<AccessibleWrap*>(thisObj->AnchorAt(aIndex)); + if (!anchor) return S_FALSE; + + void* instancePtr = nullptr; + HRESULT result = anchor->QueryInterface(IID_IUnknown, &instancePtr); + if (FAILED(result)) return result; + + aAnchor->punkVal = static_cast<IUnknown*>(instancePtr); + aAnchor->vt = VT_UNKNOWN; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHyperlink::get_anchorTarget(long aIndex, VARIANT* aAnchorTarget) { + if (!aAnchorTarget) { + return E_INVALIDARG; + } + + VariantInit(aAnchorTarget); + + Accessible* thisObj = static_cast<AccessibleWrap*>(this); + nsAutoCString uriStr; + MOZ_ASSERT(!thisObj->IsProxy()); + if (thisObj->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount())) { + return E_INVALIDARG; + } + + if (!thisObj->IsLink()) { + return S_FALSE; + } + + nsCOMPtr<nsIURI> uri = thisObj->AnchorURIAt(aIndex); + if (!uri) { + return S_FALSE; + } + + nsresult rv = uri->GetSpec(uriStr); + if (NS_FAILED(rv)) { + return GetHRESULT(rv); + } + + nsAutoString stringURI; + AppendUTF8toUTF16(uriStr, stringURI); + + aAnchorTarget->vt = VT_BSTR; + aAnchorTarget->bstrVal = + ::SysAllocStringLen(stringURI.get(), stringURI.Length()); + return aAnchorTarget->bstrVal ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleHyperlink::get_startIndex(long* aIndex) { + if (!aIndex) return E_INVALIDARG; + + *aIndex = 0; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + Accessible* thisObj = static_cast<AccessibleWrap*>(this); + if (thisObj->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!thisObj->IsLink()) return S_FALSE; + + *aIndex = thisObj->StartOffset(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHyperlink::get_endIndex(long* aIndex) { + if (!aIndex) return E_INVALIDARG; + + *aIndex = 0; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + Accessible* thisObj = static_cast<AccessibleWrap*>(this); + if (thisObj->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!thisObj->IsLink()) return S_FALSE; + + *aIndex = thisObj->EndOffset(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHyperlink::get_valid(boolean* aValid) { + if (!aValid) return E_INVALIDARG; + + *aValid = false; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + Accessible* thisObj = static_cast<AccessibleWrap*>(this); + if (thisObj->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!thisObj->IsLink()) return S_FALSE; + + *aValid = thisObj->IsLinkValid(); + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleHyperlink.h b/accessible/windows/ia2/ia2AccessibleHyperlink.h new file mode 100644 index 0000000000..c469255e1c --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleHyperlink.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 _ACCESSIBLE_HYPERLINK_H +#define _ACCESSIBLE_HYPERLINK_H + +#include "nsISupports.h" + +#include "ia2AccessibleAction.h" +#include "AccessibleHyperlink.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleHyperlink : public ia2AccessibleAction, + public IAccessibleHyperlink { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleAction + FORWARD_IACCESSIBLEACTION(ia2AccessibleAction) + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_anchor( + /* [in] */ long index, + /* [retval][out] */ VARIANT* anchor); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_anchorTarget( + /* [in] */ long index, + /* [retval][out] */ VARIANT* anchorTarget); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_startIndex( + /* [retval][out] */ long* index); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_endIndex( + /* [retval][out] */ long* index); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_valid( + /* [retval][out] */ boolean* valid); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleHypertext.cpp b/accessible/windows/ia2/ia2AccessibleHypertext.cpp new file mode 100644 index 0000000000..eed2c2cdf6 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleHypertext.cpp @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleHypertext.h" + +#include "AccessibleHypertext_i.c" + +#include "HyperTextAccessibleWrap.h" +#include "IUnknownImpl.h" + +using namespace mozilla::a11y; + +// IAccessibleHypertext + +STDMETHODIMP +ia2AccessibleHypertext::get_nHyperlinks(long* aHyperlinkCount) { + if (!aHyperlinkCount) return E_INVALIDARG; + + *aHyperlinkCount = 0; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessibleWrap* hyperText = + static_cast<HyperTextAccessibleWrap*>(this); + if (hyperText->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + *aHyperlinkCount = hyperText->LinkCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHypertext::get_hyperlink(long aLinkIndex, + IAccessibleHyperlink** aHyperlink) { + if (!aHyperlink) return E_INVALIDARG; + + *aHyperlink = nullptr; + + AccessibleWrap* hyperLink; + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessibleWrap* hyperText = + static_cast<HyperTextAccessibleWrap*>(this); + if (hyperText->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + hyperLink = static_cast<AccessibleWrap*>(hyperText->LinkAt(aLinkIndex)); + + if (!hyperLink) return E_FAIL; + + *aHyperlink = static_cast<IAccessibleHyperlink*>(hyperLink); + (*aHyperlink)->AddRef(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHypertext::get_hyperlinkIndex(long aCharIndex, + long* aHyperlinkIndex) { + if (!aHyperlinkIndex) return E_INVALIDARG; + + *aHyperlinkIndex = 0; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessibleWrap* hyperAcc = + static_cast<HyperTextAccessibleWrap*>(this); + if (hyperAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + *aHyperlinkIndex = hyperAcc->LinkIndexAtOffset(aCharIndex); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHypertext::get_hyperlinks(IAccessibleHyperlink*** aHyperlinks, + long* aNHyperlinks) { + if (!aHyperlinks || !aNHyperlinks) { + return E_INVALIDARG; + } + + *aHyperlinks = nullptr; + *aNHyperlinks = 0; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessibleWrap* hyperText = + static_cast<HyperTextAccessibleWrap*>(this); + if (hyperText->IsDefunct()) { + 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) { + AccessibleWrap* hyperLink = + static_cast<AccessibleWrap*>(hyperText->LinkAt(i)); + MOZ_ASSERT(hyperLink); + (*aHyperlinks)[i] = static_cast<IAccessibleHyperlink*>(hyperLink); + (*aHyperlinks)[i]->AddRef(); + } + + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleHypertext.h b/accessible/windows/ia2/ia2AccessibleHypertext.h new file mode 100644 index 0000000000..2cdda4cf75 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleHypertext.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_HYPERTEXT_H +#define _ACCESSIBLE_HYPERTEXT_H + +#include "nsISupports.h" + +#include "ia2AccessibleText.h" +#include "AccessibleHypertext2.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleHypertext : public ia2AccessibleText, + public IAccessibleHypertext2 { + public: + // IAccessibleText + FORWARD_IACCESSIBLETEXT(ia2AccessibleText) + + // IAccessibleHypertext + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nHyperlinks( + /* [retval][out] */ long* hyperlinkCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlink( + /* [in] */ long index, + /* [retval][out] */ IAccessibleHyperlink** hyperlink); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlinkIndex( + /* [in] */ long charIndex, + /* [retval][out] */ long* hyperlinkIndex); + + // IAccessibleHypertext2 + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlinks( + /* [out, size_is(,*nHyperlinks)] */ IAccessibleHyperlink*** hyperlinks, + /* [out, retval] */ long* nHyperlinks); +}; + +} // 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..ad198bb759 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleImage.cpp @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleImage.h" + +#include "AccessibleImage_i.c" + +#include "ImageAccessibleWrap.h" +#include "IUnknownImpl.h" +#include "nsIAccessibleTypes.h" + +#include "nsString.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +// IUnknown + +STDMETHODIMP +ia2AccessibleImage::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleImage == iid) { + *ppv = static_cast<IAccessibleImage*>(this); + (static_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +// IAccessibleImage + +STDMETHODIMP +ia2AccessibleImage::get_description(BSTR* aDescription) { + if (!aDescription) return E_INVALIDARG; + + *aDescription = nullptr; + + ImageAccessibleWrap* acc = static_cast<ImageAccessibleWrap*>(this); + if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + nsAutoString description; + acc->Name(description); + if (description.IsEmpty()) return S_FALSE; + + *aDescription = ::SysAllocStringLen(description.get(), description.Length()); + return *aDescription ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleImage::get_imagePosition(enum IA2CoordinateType aCoordType, + long* aX, long* aY) { + if (!aX || !aY) return E_INVALIDARG; + + *aX = 0; + *aY = 0; + + ImageAccessibleWrap* imageAcc = static_cast<ImageAccessibleWrap*>(this); + if (imageAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + uint32_t geckoCoordType = + (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) + ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE + : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + + nsIntPoint pos = imageAcc->Position(geckoCoordType); + *aX = pos.x; + *aY = pos.y; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleImage::get_imageSize(long* aHeight, long* aWidth) { + if (!aHeight || !aWidth) return E_INVALIDARG; + + *aHeight = 0; + *aWidth = 0; + + ImageAccessibleWrap* imageAcc = static_cast<ImageAccessibleWrap*>(this); + if (imageAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + nsIntSize size = imageAcc->Size(); + *aHeight = size.width; + *aWidth = size.height; + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleImage.h b/accessible/windows/ia2/ia2AccessibleImage.h new file mode 100644 index 0000000000..23c7b74f77 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleImage.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_IMAGE_H +#define _ACCESSIBLE_IMAGE_H + +#include "AccessibleImage.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleImage : public IAccessibleImage { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleImage + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_description( + /* [retval][out] */ BSTR* description); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_imagePosition( + /* [in] */ enum IA2CoordinateType coordinateType, + /* [out] */ long* x, + /* [retval][out] */ long* y); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_imageSize( + /* [out] */ long* height, + /* [retval][out] */ long* width); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleRelation.cpp b/accessible/windows/ia2/ia2AccessibleRelation.cpp new file mode 100644 index 0000000000..1e920c5376 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleRelation.cpp @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleRelation.h" + +#include "Relation.h" +#include "nsID.h" + +#include "AccessibleRelation_i.c" + +using namespace mozilla::a11y; + +ia2AccessibleRelation::ia2AccessibleRelation(RelationType aType, Relation* aRel) + : mType(aType) { + Accessible* target = nullptr; + while ((target = aRel->Next())) mTargets.AppendElement(target); +} + +// IUnknown + +IMPL_IUNKNOWN_QUERY_HEAD(ia2AccessibleRelation) +IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleRelation) +IMPL_IUNKNOWN_QUERY_IFACE(IUnknown) +IMPL_IUNKNOWN_QUERY_TAIL + +// IAccessibleRelation + +STDMETHODIMP +ia2AccessibleRelation::get_relationType(BSTR* aRelationType) { + 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; + + AccessibleWrap* target = + static_cast<AccessibleWrap*>(mTargets[aTargetIndex].get()); + *aTarget = static_cast<IAccessible*>(target); + (*aTarget)->AddRef(); + + 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..afed4be56e --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleRelation.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _NS_ACCESSIBLE_RELATION_WRAP_H +#define _NS_ACCESSIBLE_RELATION_WRAP_H + +#include "Accessible.h" +#include "IUnknownImpl.h" + +#include <utility> +#include "nsTArray.h" + +#include "AccessibleRelation.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleRelation final : public IAccessibleRelation { + public: + ia2AccessibleRelation(RelationType aType, Relation* aRel); + + ia2AccessibleRelation(RelationType aType, + nsTArray<RefPtr<Accessible>>&& aTargets) + : mType(aType), mTargets(std::move(aTargets)) {} + + // IUnknown + DECL_IUNKNOWN + + // IAccessibleRelation + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relationType( + /* [retval][out] */ BSTR* relationType); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedRelationType( + /* [retval][out] */ BSTR* localizedRelationType); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nTargets( + /* [retval][out] */ long* nTargets); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_target( + /* [in] */ long targetIndex, + /* [retval][out] */ IUnknown** target); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_targets( + /* [in] */ long maxTargets, + /* [length_is][size_is][out] */ IUnknown** target, + /* [retval][out] */ long* nTargets); + + inline bool HasTargets() const { return mTargets.Length(); } + + private: + ia2AccessibleRelation(); + ia2AccessibleRelation(const ia2AccessibleRelation&); + ia2AccessibleRelation& operator=(const ia2AccessibleRelation&); + + RelationType mType; + nsTArray<RefPtr<Accessible>> mTargets; +}; + +/** + * Gecko to IAccessible2 relation types map. + */ + +const WCHAR* const IA2_RELATION_NULL = L""; + +#define RELATIONTYPE(geckoType, name, atkType, msaaType, ia2Type) \ + std::pair<RelationType, const WCHAR* const>(RelationType::geckoType, ia2Type), + +static const std::pair<RelationType, const WCHAR* const> sRelationTypePairs[] = + { +#include "RelationTypeMap.h" +}; + +#undef RELATIONTYPE + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleTable.cpp b/accessible/windows/ia2/ia2AccessibleTable.cpp new file mode 100644 index 0000000000..7150c13da2 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTable.cpp @@ -0,0 +1,540 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleTable.h" + +#include "Accessible2.h" +#include "AccessibleTable_i.c" +#include "AccessibleTable2_i.c" + +#include "AccessibleWrap.h" +#include "IUnknownImpl.h" +#include "Statistics.h" +#include "TableAccessible.h" + +#include "nsCOMPtr.h" +#include "nsString.h" + +using namespace mozilla::a11y; + +// IUnknown + +STDMETHODIMP +ia2AccessibleTable::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleTable == iid) { + statistics::IAccessibleTableUsed(); + *ppv = static_cast<IAccessibleTable*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + if (IID_IAccessibleTable2 == iid) { + *ppv = static_cast<IAccessibleTable2*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +//////////////////////////////////////////////////////////////////////////////// +// IAccessibleTable + +STDMETHODIMP +ia2AccessibleTable::get_accessibleAt(long aRowIdx, long aColIdx, + IUnknown** aAccessible) { + return get_cellAt(aRowIdx, aColIdx, aAccessible); +} + +STDMETHODIMP +ia2AccessibleTable::get_caption(IUnknown** aAccessible) { + if (!aAccessible) return E_INVALIDARG; + + *aAccessible = nullptr; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + AccessibleWrap* caption = static_cast<AccessibleWrap*>(mTable->Caption()); + if (!caption) return S_FALSE; + + (*aAccessible = static_cast<IAccessible*>(caption))->AddRef(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_childIndex(long aRowIdx, long aColIdx, + long* aChildIdx) { + if (!aChildIdx) return E_INVALIDARG; + + *aChildIdx = 0; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || aColIdx < 0 || + static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() || + static_cast<uint32_t>(aColIdx) >= mTable->ColCount()) + return E_INVALIDARG; + + *aChildIdx = mTable->CellIndexAt(aRowIdx, aColIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_columnDescription(long aColIdx, BSTR* aDescription) { + if (!aDescription) return E_INVALIDARG; + + *aDescription = nullptr; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount()) + return E_INVALIDARG; + + nsAutoString descr; + mTable->ColDescription(aColIdx, descr); + if (descr.IsEmpty()) return S_FALSE; + + *aDescription = ::SysAllocStringLen(descr.get(), descr.Length()); + return *aDescription ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleTable::get_columnExtentAt(long aRowIdx, long aColIdx, + long* aSpan) { + if (!aSpan) return E_INVALIDARG; + + *aSpan = 0; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || aColIdx < 0 || + static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() || + static_cast<uint32_t>(aColIdx) >= mTable->ColCount()) + return E_INVALIDARG; + + *aSpan = mTable->ColExtentAt(aRowIdx, aColIdx); + return S_OK; +} + +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; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aCellIdx < 0) { + return E_INVALIDARG; + } + + long colIdx = mTable->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; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + *aColCount = mTable->ColCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_nRows(long* aRowCount) { + if (!aRowCount) return E_INVALIDARG; + + *aRowCount = 0; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + *aRowCount = mTable->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; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + *aColCount = mTable->SelectedColCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_nSelectedRows(long* aRowCount) { + if (!aRowCount) return E_INVALIDARG; + + *aRowCount = 0; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + *aRowCount = mTable->SelectedRowCount(); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_rowDescription(long aRowIdx, BSTR* aDescription) { + if (!aDescription) return E_INVALIDARG; + + *aDescription = nullptr; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount()) + return E_INVALIDARG; + + nsAutoString descr; + mTable->RowDescription(aRowIdx, descr); + if (descr.IsEmpty()) return S_FALSE; + + *aDescription = ::SysAllocStringLen(descr.get(), descr.Length()); + return *aDescription ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleTable::get_rowExtentAt(long aRowIdx, long aColIdx, long* aSpan) { + if (!aSpan) return E_INVALIDARG; + + *aSpan = 0; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || aColIdx < 0 || + static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() || + static_cast<uint32_t>(aColIdx) >= mTable->ColCount()) + return E_INVALIDARG; + + *aSpan = mTable->RowExtentAt(aRowIdx, aColIdx); + return S_OK; +} + +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; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aCellIdx < 0) { + return E_INVALIDARG; + } + + long rowIdx = mTable->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; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + AutoTArray<uint32_t, 30> cellIndices; + mTable->SelectedCellIndices(&cellIndices); + + uint32_t maxCells = cellIndices.Length(); + if (maxCells == 0) return S_FALSE; + + *aChildren = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCells)); + *aNChildren = maxCells; + for (uint32_t i = 0; i < maxCells; i++) (*aChildren)[i] = cellIndices[i]; + + return S_OK; +} + +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; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount()) + return E_INVALIDARG; + + *aIsSelected = mTable->IsColSelected(aColIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_isRowSelected(long aRowIdx, boolean* aIsSelected) { + if (!aIsSelected) return E_INVALIDARG; + + *aIsSelected = false; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount()) + return E_INVALIDARG; + + *aIsSelected = mTable->IsRowSelected(aRowIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_isSelected(long aRowIdx, long aColIdx, + boolean* aIsSelected) { + if (!aIsSelected) return E_INVALIDARG; + + *aIsSelected = false; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || aColIdx < 0 || + static_cast<uint32_t>(aColIdx) >= mTable->ColCount() || + static_cast<uint32_t>(aRowIdx) >= mTable->RowCount()) + return E_INVALIDARG; + + *aIsSelected = mTable->IsCellSelected(aRowIdx, aColIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::selectRow(long aRowIdx) { + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount()) + return E_INVALIDARG; + + mTable->SelectRow(aRowIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::selectColumn(long aColIdx) { + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount()) + return E_INVALIDARG; + + mTable->SelectCol(aColIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::unselectRow(long aRowIdx) { + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount()) + return E_INVALIDARG; + + mTable->UnselectRow(aRowIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::unselectColumn(long aColIdx) { + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount()) + return E_INVALIDARG; + + mTable->UnselectCol(aColIdx); + return S_OK; +} + +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; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + if (aCellIdx < 0) { + return E_INVALIDARG; + } + + int32_t colIdx = 0, rowIdx = 0; + mTable->RowAndColIndicesAt(aCellIdx, &rowIdx, &colIdx); + if (rowIdx == -1 || colIdx == -1) { // Indicates an error. + return E_INVALIDARG; + } + + *aRowIdx = rowIdx; + *aColIdx = colIdx; + *aRowExtents = mTable->RowExtentAt(rowIdx, colIdx); + *aColExtents = mTable->ColExtentAt(rowIdx, colIdx); + *aIsSelected = mTable->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; + + if (!mTable) return CO_E_OBJNOTCONNECTED; + + AccessibleWrap* cell = + static_cast<AccessibleWrap*>(mTable->CellAt(aRowIdx, aColIdx)); + if (!cell) return E_INVALIDARG; + + (*aCell = static_cast<IAccessible*>(cell))->AddRef(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_nSelectedCells(long* aCellCount) { + if (!aCellCount) return E_INVALIDARG; + + *aCellCount = 0; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + *aCellCount = mTable->SelectedCellCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_selectedCells(IUnknown*** aCells, + long* aNSelectedCells) { + if (!aCells || !aNSelectedCells) return E_INVALIDARG; + + *aCells = nullptr; + *aNSelectedCells = 0; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + AutoTArray<Accessible*, 30> cells; + mTable->SelectedCells(&cells); + if (cells.IsEmpty()) return S_FALSE; + + *aCells = static_cast<IUnknown**>( + ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length())); + if (!*aCells) return E_OUTOFMEMORY; + + for (uint32_t i = 0; i < cells.Length(); i++) { + (*aCells)[i] = + static_cast<IAccessible*>(static_cast<AccessibleWrap*>(cells[i])); + ((*aCells)[i])->AddRef(); + } + + *aNSelectedCells = cells.Length(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_selectedColumns(long** aColumns, long* aNColumns) { + if (!aColumns || !aNColumns) return E_INVALIDARG; + + *aColumns = nullptr; + *aNColumns = 0; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + AutoTArray<uint32_t, 30> colIndices; + mTable->SelectedColIndices(&colIndices); + + uint32_t maxCols = colIndices.Length(); + if (maxCols == 0) return S_FALSE; + + *aColumns = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCols)); + *aNColumns = maxCols; + for (uint32_t i = 0; i < maxCols; i++) (*aColumns)[i] = colIndices[i]; + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_selectedRows(long** aRows, long* aNRows) { + if (!aRows || !aNRows) return E_INVALIDARG; + + *aRows = nullptr; + *aNRows = 0; + if (!mTable) return CO_E_OBJNOTCONNECTED; + + AutoTArray<uint32_t, 30> rowIndices; + mTable->SelectedRowIndices(&rowIndices); + + uint32_t maxRows = rowIndices.Length(); + if (maxRows == 0) return S_FALSE; + + *aRows = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxRows)); + *aNRows = maxRows; + for (uint32_t i = 0; i < maxRows; i++) (*aRows)[i] = rowIndices[i]; + + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleTable.h b/accessible/windows/ia2/ia2AccessibleTable.h new file mode 100644 index 0000000000..97b7103d85 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTable.h @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_TABLE_H +#define _ACCESSIBLE_TABLE_H + +#include "AccessibleTable.h" +#include "AccessibleTable2.h" + +namespace mozilla { +namespace a11y { + +class TableAccessible; + +class ia2AccessibleTable : public IAccessibleTable, public IAccessibleTable2 { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleTable + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_accessibleAt( + /* [in] */ long row, + /* [in] */ long column, + /* [retval][out] */ IUnknown** accessible); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_caption( + /* [retval][out] */ IUnknown** accessible); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_childIndex( + /* [in] */ long rowIndex, + /* [in] */ long columnIndex, + /* [retval][out] */ long* childIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnDescription( + /* [in] */ long column, + /* [retval][out] */ BSTR* description); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnExtentAt( + /* [in] */ long row, + /* [in] */ long column, + /* [retval][out] */ long* nColumnsSpanned); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnHeader( + /* [out] */ IAccessibleTable** accessibleTable, + /* [retval][out] */ long* startingRowIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnIndex( + /* [in] */ long childIndex, + /* [retval][out] */ long* columnIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nColumns( + /* [retval][out] */ long* columnCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nRows( + /* [retval][out] */ long* rowCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedChildren( + /* [retval][out] */ long* childCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedColumns( + /* [retval][out] */ long* columnCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedRows( + /* [retval][out] */ long* rowCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowDescription( + /* [in] */ long row, + /* [retval][out] */ BSTR* description); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowExtentAt( + /* [in] */ long row, + /* [in] */ long column, + /* [retval][out] */ long* nRowsSpanned); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowHeader( + /* [out] */ IAccessibleTable** accessibleTable, + /* [retval][out] */ long* startingColumnIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowIndex( + /* [in] */ long childIndex, + /* [retval][out] */ long* rowIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedChildren( + /* [in] */ long maxChildren, + /* [length_is][length_is][size_is][size_is][out] */ long** children, + /* [retval][out] */ long* nChildren); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedColumns( + /* [in] */ long maxColumns, + /* [length_is][length_is][size_is][size_is][out] */ long** columns, + /* [retval][out] */ long* nColumns); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedRows( + /* [in] */ long maxRows, + /* [length_is][length_is][size_is][size_is][out] */ long** rows, + /* [retval][out] */ long* nRows); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_summary( + /* [retval][out] */ IUnknown** accessible); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isColumnSelected( + /* [in] */ long column, + /* [retval][out] */ boolean* isSelected); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isRowSelected( + /* [in] */ long row, + /* [retval][out] */ boolean* isSelected); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isSelected( + /* [in] */ long row, + /* [in] */ long column, + /* [retval][out] */ boolean* isSelected); + + virtual HRESULT STDMETHODCALLTYPE selectRow( + /* [in] */ long row); + + virtual HRESULT STDMETHODCALLTYPE selectColumn( + /* [in] */ long column); + + virtual HRESULT STDMETHODCALLTYPE unselectRow( + /* [in] */ long row); + + virtual HRESULT STDMETHODCALLTYPE unselectColumn( + /* [in] */ long column); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowColumnExtentsAtIndex( + /* [in] */ long index, + /* [out] */ long* row, + /* [out] */ long* column, + /* [out] */ long* rowExtents, + /* [out] */ long* columnExtents, + /* [retval][out] */ boolean* isSelected); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_modelChange( + /* [retval][out] */ IA2TableModelChange* modelChange); + + // IAccessibleTable2 + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_cellAt( + /* [in] */ long row, + /* [in] */ long column, + /* [out, retval] */ IUnknown** cell); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedCells( + /* [out, retval] */ long* cellCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedCells( + /* [out, size_is(,*nSelectedCells,)] */ IUnknown*** cells, + /* [out, retval] */ long* nSelectedCells); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedColumns( + /* [out, size_is(,*nColumns)] */ long** selectedColumns, + /* [out, retval] */ long* nColumns); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedRows( + /* [out, size_is(,*nRows)] */ long** selectedRows, + /* [out, retval] */ long* nRows); + + protected: + ia2AccessibleTable(TableAccessible* aTable) : mTable(aTable) {} + + TableAccessible* mTable; +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleTableCell.cpp b/accessible/windows/ia2/ia2AccessibleTableCell.cpp new file mode 100644 index 0000000000..c1589d0acd --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTableCell.cpp @@ -0,0 +1,187 @@ +/* -*- 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 "AccessibleWrap.h" +#include "TableAccessible.h" +#include "TableCellAccessible.h" +#include "IUnknownImpl.h" + +#include "nsCOMPtr.h" +#include "nsString.h" + +using namespace mozilla::a11y; + +// IUnknown + +STDMETHODIMP +ia2AccessibleTableCell::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleTableCell == iid) { + *ppv = static_cast<IAccessibleTableCell*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +//////////////////////////////////////////////////////////////////////////////// +// IAccessibleTableCell + +STDMETHODIMP +ia2AccessibleTableCell::get_table(IUnknown** aTable) { + if (!aTable) return E_INVALIDARG; + + *aTable = nullptr; + if (!mTableCell) return CO_E_OBJNOTCONNECTED; + + TableAccessible* table = mTableCell->Table(); + if (!table) return E_FAIL; + + AccessibleWrap* wrap = static_cast<AccessibleWrap*>(table->AsAccessible()); + *aTable = static_cast<IAccessible*>(wrap); + (*aTable)->AddRef(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_columnExtent(long* aSpan) { + if (!aSpan) return E_INVALIDARG; + + *aSpan = 0; + if (!mTableCell) return CO_E_OBJNOTCONNECTED; + + *aSpan = mTableCell->ColExtent(); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_columnHeaderCells(IUnknown*** aCellAccessibles, + long* aNColumnHeaderCells) { + if (!aCellAccessibles || !aNColumnHeaderCells) return E_INVALIDARG; + + *aCellAccessibles = nullptr; + *aNColumnHeaderCells = 0; + if (!mTableCell) return CO_E_OBJNOTCONNECTED; + + AutoTArray<Accessible*, 10> cells; + mTableCell->ColHeaderCells(&cells); + + *aNColumnHeaderCells = cells.Length(); + *aCellAccessibles = static_cast<IUnknown**>( + ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length())); + + if (!*aCellAccessibles) return E_OUTOFMEMORY; + + for (uint32_t i = 0; i < cells.Length(); i++) { + AccessibleWrap* cell = static_cast<AccessibleWrap*>(cells[i]); + (*aCellAccessibles)[i] = static_cast<IAccessible*>(cell); + (*aCellAccessibles)[i]->AddRef(); + } + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_columnIndex(long* aColIdx) { + if (!aColIdx) return E_INVALIDARG; + + *aColIdx = -1; + if (!mTableCell) return CO_E_OBJNOTCONNECTED; + + *aColIdx = mTableCell->ColIdx(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_rowExtent(long* aSpan) { + if (!aSpan) return E_INVALIDARG; + + *aSpan = 0; + if (!mTableCell) return CO_E_OBJNOTCONNECTED; + + *aSpan = mTableCell->RowExtent(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_rowHeaderCells(IUnknown*** aCellAccessibles, + long* aNRowHeaderCells) { + if (!aCellAccessibles || !aNRowHeaderCells) return E_INVALIDARG; + + *aCellAccessibles = nullptr; + *aNRowHeaderCells = 0; + if (!mTableCell) return CO_E_OBJNOTCONNECTED; + + AutoTArray<Accessible*, 10> cells; + mTableCell->RowHeaderCells(&cells); + + *aNRowHeaderCells = cells.Length(); + *aCellAccessibles = static_cast<IUnknown**>( + ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length())); + if (!*aCellAccessibles) return E_OUTOFMEMORY; + + for (uint32_t i = 0; i < cells.Length(); i++) { + AccessibleWrap* cell = static_cast<AccessibleWrap*>(cells[i]); + (*aCellAccessibles)[i] = static_cast<IAccessible*>(cell); + (*aCellAccessibles)[i]->AddRef(); + } + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_rowIndex(long* aRowIdx) { + if (!aRowIdx) return E_INVALIDARG; + + *aRowIdx = -1; + if (!mTableCell) return CO_E_OBJNOTCONNECTED; + + *aRowIdx = mTableCell->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; + if (!mTableCell) return CO_E_OBJNOTCONNECTED; + + *aRowIdx = mTableCell->RowIdx(); + *aColIdx = mTableCell->ColIdx(); + *aRowExtents = mTableCell->RowExtent(); + *aColExtents = mTableCell->ColExtent(); + *aIsSelected = mTableCell->Selected(); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_isSelected(boolean* aIsSelected) { + if (!aIsSelected) return E_INVALIDARG; + + *aIsSelected = false; + if (!mTableCell) return CO_E_OBJNOTCONNECTED; + + *aIsSelected = mTableCell->Selected(); + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleTableCell.h b/accessible/windows/ia2/ia2AccessibleTableCell.h new file mode 100644 index 0000000000..bb7504f20c --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTableCell.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_TABLECELL_H +#define _ACCESSIBLE_TABLECELL_H + +#include "AccessibleTableCell.h" + +namespace mozilla { +namespace a11y { +class TableCellAccessible; + +class ia2AccessibleTableCell : public IAccessibleTableCell { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleTableCell + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_table( + /* [out, retval] */ IUnknown** table); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnExtent( + /* [out, retval] */ long* nColumnsSpanned); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnHeaderCells( + /* [out, size_is(,*nColumnHeaderCells,)] */ IUnknown*** cellAccessibles, + /* [out, retval] */ long* nColumnHeaderCells); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnIndex( + /* [out, retval] */ long* columnIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowExtent( + /* [out, retval] */ long* nRowsSpanned); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowHeaderCells( + /* [out, size_is(,*nRowHeaderCells,)] */ IUnknown*** cellAccessibles, + /* [out, retval] */ long* nRowHeaderCells); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowIndex( + /* [out, retval] */ long* rowIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowColumnExtents( + /* [out] */ long* row, + /* [out] */ long* column, + /* [out] */ long* rowExtents, + /* [out] */ long* columnExtents, + /* [out, retval] */ boolean* isSelected); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isSelected( + /* [out, retval] */ boolean* isSelected); + + protected: + ia2AccessibleTableCell(TableCellAccessible* aTableCell) + : mTableCell(aTableCell) {} + + TableCellAccessible* mTableCell; +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleText.cpp b/accessible/windows/ia2/ia2AccessibleText.cpp new file mode 100644 index 0000000000..85cd7113f2 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleText.cpp @@ -0,0 +1,464 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleText.h" + +#include "AccessibleText_i.c" + +#include "HyperTextAccessibleWrap.h" +#include "HyperTextAccessible-inl.h" +#include "ProxyWrappers.h" +#include "mozilla/ClearOnShutdown.h" + +using namespace mozilla::a11y; + +StaticRefPtr<HyperTextAccessibleWrap> ia2AccessibleText::sLastTextChangeAcc; +StaticAutoPtr<nsString> ia2AccessibleText::sLastTextChangeString; +uint32_t ia2AccessibleText::sLastTextChangeStart = 0; +uint32_t ia2AccessibleText::sLastTextChangeEnd = 0; +bool ia2AccessibleText::sLastTextChangeWasInsert = false; + +// IAccessibleText + +STDMETHODIMP +ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset) { + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + return textAcc->AddToSelection(aStartOffset, aEndOffset) ? S_OK + : E_INVALIDARG; +} + +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; + HRESULT hr; + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + nsCOMPtr<nsIPersistentProperties> attributes = + textAcc->TextAttributes(true, aOffset, &startOffset, &endOffset); + + hr = AccessibleWrap::ConvertToIA2Attributes(attributes, aTextAttributes); + if (FAILED(hr)) return hr; + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::get_caretOffset(long* aOffset) { + if (!aOffset) return E_INVALIDARG; + + *aOffset = -1; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + *aOffset = textAcc->CaretOffset(); + + return *aOffset != -1 ? S_OK : S_FALSE; +} + +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; + nsIntRect rect; + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) 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; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + 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; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + *aOffset = textAcc->OffsetAtPoint(aX, aY, geckoCoordType); + + return *aOffset == -1 ? S_FALSE : S_OK; +} + +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; + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->SelectionBoundsAt(aSelectionIndex, &startOffset, &endOffset)) { + return E_INVALIDARG; + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR* aText) { + if (!aText) return E_INVALIDARG; + + *aText = nullptr; + + nsAutoString text; + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) { + return E_INVALIDARG; + } + + textAcc->TextSubstring(aStartOffset, aEndOffset, text); + + if (text.IsEmpty()) return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; +} + +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; + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + nsAutoString text; + int32_t startOffset = 0, endOffset = 0; + + if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { + startOffset = 0; + endOffset = textAcc->CharacterCount(); + textAcc->TextSubstring(startOffset, endOffset, text); + } else { + AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); + if (boundaryType == -1) return S_FALSE; + + textAcc->TextBeforeOffset(aOffset, boundaryType, &startOffset, &endOffset, + text); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + if (text.IsEmpty()) return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; +} + +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; + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + nsAutoString text; + int32_t startOffset = 0, endOffset = 0; + + if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { + startOffset = 0; + endOffset = textAcc->CharacterCount(); + textAcc->TextSubstring(startOffset, endOffset, text); + } else { + AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); + if (boundaryType == -1) return S_FALSE; + textAcc->TextAfterOffset(aOffset, boundaryType, &startOffset, &endOffset, + text); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + if (text.IsEmpty()) return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; +} + +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; + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + nsAutoString text; + int32_t startOffset = 0, endOffset = 0; + if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { + startOffset = 0; + endOffset = textAcc->CharacterCount(); + textAcc->TextSubstring(startOffset, endOffset, text); + } else { + AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); + if (boundaryType == -1) return S_FALSE; + textAcc->TextAtOffset(aOffset, boundaryType, &startOffset, &endOffset, + text); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + if (text.IsEmpty()) return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleText::removeSelection(long aSelectionIndex) { + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + return textAcc->RemoveFromSelection(aSelectionIndex) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP +ia2AccessibleText::setCaretOffset(long aOffset) { + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + textAcc->SetCaretOffset(aOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::setSelection(long aSelectionIndex, long aStartOffset, + long aEndOffset) { + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + return textAcc->SetSelectionBoundsAt(aSelectionIndex, aStartOffset, + aEndOffset) + ? S_OK + : E_INVALIDARG; +} + +STDMETHODIMP +ia2AccessibleText::get_nCharacters(long* aNCharacters) { + if (!aNCharacters) return E_INVALIDARG; + *aNCharacters = 0; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + *aNCharacters = textAcc->CharacterCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex, + enum IA2ScrollType aScrollType) { + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) return E_INVALIDARG; + + textAcc->ScrollSubstringTo(aStartIndex, aEndIndex, aScrollType); + return S_OK; +} + +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; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) return E_INVALIDARG; + + textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex, geckoCoordType, aX, + aY); + return S_OK; +} + +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 != this) return S_OK; + + aText->start = sLastTextChangeStart; + aText->end = sLastTextChangeEnd; + + if (sLastTextChangeString->IsEmpty()) return S_FALSE; + + aText->text = ::SysAllocStringLen(sLastTextChangeString->get(), + sLastTextChangeString->Length()); + return aText->text ? S_OK : E_OUTOFMEMORY; +} + +AccessibleTextBoundary ia2AccessibleText::GetGeckoTextBoundary( + enum IA2TextBoundaryType aBoundaryType) { + switch (aBoundaryType) { + case IA2_TEXT_BOUNDARY_CHAR: + return nsIAccessibleText::BOUNDARY_CHAR; + case IA2_TEXT_BOUNDARY_WORD: + return nsIAccessibleText::BOUNDARY_WORD_START; + case IA2_TEXT_BOUNDARY_LINE: + return nsIAccessibleText::BOUNDARY_LINE_START; + case IA2_TEXT_BOUNDARY_PARAGRAPH: + return nsIAccessibleText::BOUNDARY_PARAGRAPH; + // case IA2_TEXT_BOUNDARY_SENTENCE: + // XXX: not implemented + default: + return -1; + } +} + +void ia2AccessibleText::InitTextChangeData() { + ClearOnShutdown(&sLastTextChangeAcc); + ClearOnShutdown(&sLastTextChangeString); +} + +void ia2AccessibleText::UpdateTextChangeData(HyperTextAccessibleWrap* aAcc, + bool aInsert, const nsString& aStr, + int32_t aStart, uint32_t aLen) { + if (!sLastTextChangeString) sLastTextChangeString = new nsString(); + + sLastTextChangeAcc = aAcc; + sLastTextChangeStart = aStart; + sLastTextChangeEnd = aStart + aLen; + sLastTextChangeWasInsert = aInsert; + *sLastTextChangeString = aStr; +} diff --git a/accessible/windows/ia2/ia2AccessibleText.h b/accessible/windows/ia2/ia2AccessibleText.h new file mode 100644 index 0000000000..cd4f1ad5a7 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleText.h @@ -0,0 +1,234 @@ +/* -*- 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 "AccessibleText.h" + +namespace mozilla { +namespace a11y { +class HyperTextAccessibleWrap; + +class ia2AccessibleText : public IAccessibleText { + public: + // IAccessibleText + virtual HRESULT STDMETHODCALLTYPE addSelection( + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_attributes( + /* [in] */ long offset, + /* [out] */ long* startOffset, + /* [out] */ long* endOffset, + /* [retval][out] */ BSTR* textAttributes); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_caretOffset( + /* [retval][out] */ long* offset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_characterExtents( + /* [in] */ long offset, + /* [in] */ enum IA2CoordinateType coordType, + /* [out] */ long* x, + /* [out] */ long* y, + /* [out] */ long* width, + /* [retval][out] */ long* height); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelections( + /* [retval][out] */ long* nSelections); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_offsetAtPoint( + /* [in] */ long x, + /* [in] */ long y, + /* [in] */ enum IA2CoordinateType coordType, + /* [retval][out] */ long* offset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selection( + /* [in] */ long selectionIndex, + /* [out] */ long* startOffset, + /* [retval][out] */ long* endOffset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_text( + /* [in] */ long startOffset, + /* [in] */ long endOffset, + /* [retval][out] */ BSTR* text); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_textBeforeOffset( + /* [in] */ long offset, + /* [in] */ enum IA2TextBoundaryType boundaryType, + /* [out] */ long* startOffset, + /* [out] */ long* endOffset, + /* [retval][out] */ BSTR* text); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_textAfterOffset( + /* [in] */ long offset, + /* [in] */ enum IA2TextBoundaryType boundaryType, + /* [out] */ long* startOffset, + /* [out] */ long* endOffset, + /* [retval][out] */ BSTR* text); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_textAtOffset( + /* [in] */ long offset, + /* [in] */ enum IA2TextBoundaryType boundaryType, + /* [out] */ long* startOffset, + /* [out] */ long* endOffset, + /* [retval][out] */ BSTR* text); + + virtual HRESULT STDMETHODCALLTYPE removeSelection( + /* [in] */ long selectionIndex); + + virtual HRESULT STDMETHODCALLTYPE setCaretOffset( + /* [in] */ long offset); + + virtual HRESULT STDMETHODCALLTYPE setSelection( + /* [in] */ long selectionIndex, + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nCharacters( + /* [retval][out] */ long* nCharacters); + + virtual HRESULT STDMETHODCALLTYPE scrollSubstringTo( + /* [in] */ long startIndex, + /* [in] */ long endIndex, + /* [in] */ enum IA2ScrollType scrollType); + + virtual HRESULT STDMETHODCALLTYPE scrollSubstringToPoint( + /* [in] */ long startIndex, + /* [in] */ long endIndex, + /* [in] */ enum IA2CoordinateType coordinateType, + /* [in] */ long x, + /* [in] */ long y); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_newText( + /* [retval][out] */ IA2TextSegment* newText); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_oldText( + /* [retval][out] */ IA2TextSegment* oldText); + + static void InitTextChangeData(); + static void UpdateTextChangeData(HyperTextAccessibleWrap* aAcc, bool aInsert, + const nsString& aStr, int32_t aStart, + uint32_t aLen); + + protected: + static StaticRefPtr<HyperTextAccessibleWrap> sLastTextChangeAcc; + static StaticAutoPtr<nsString> sLastTextChangeString; + static bool sLastTextChangeWasInsert; + static uint32_t sLastTextChangeStart; + static uint32_t sLastTextChangeEnd; + + private: + HRESULT GetModifiedText(bool aGetInsertedText, IA2TextSegment* aNewText); + AccessibleTextBoundary GetGeckoTextBoundary( + enum IA2TextBoundaryType coordinateType); +}; + +} // namespace a11y +} // namespace mozilla + +#define FORWARD_IACCESSIBLETEXT(Class) \ + virtual HRESULT STDMETHODCALLTYPE addSelection(long startOffset, \ + long endOffset) { \ + return Class::addSelection(startOffset, endOffset); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_attributes( \ + long offset, long* startOffset, long* endOffset, BSTR* textAttributes) { \ + return Class::get_attributes(offset, startOffset, endOffset, \ + textAttributes); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_caretOffset(long* offset) { \ + return Class::get_caretOffset(offset); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_characterExtents( \ + long offset, enum IA2CoordinateType coordType, long* x, long* y, \ + long* width, long* height) { \ + return Class::get_characterExtents(offset, coordType, x, y, width, \ + height); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_nSelections(long* nSelections) { \ + return Class::get_nSelections(nSelections); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_offsetAtPoint( \ + long x, long y, enum IA2CoordinateType coordType, long* offset) { \ + return Class::get_offsetAtPoint(x, y, coordType, offset); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_selection( \ + long selectionIndex, long* startOffset, long* endOffset) { \ + return Class::get_selection(selectionIndex, startOffset, endOffset); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_text(long startOffset, long endOffset, \ + BSTR* text) { \ + return Class::get_text(startOffset, endOffset, text); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_textBeforeOffset( \ + long offset, enum IA2TextBoundaryType boundaryType, long* startOffset, \ + long* endOffset, BSTR* text) { \ + return Class::get_textBeforeOffset(offset, boundaryType, startOffset, \ + endOffset, text); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_textAfterOffset( \ + long offset, enum IA2TextBoundaryType boundaryType, long* startOffset, \ + long* endOffset, BSTR* text) { \ + return Class::get_textAfterOffset(offset, boundaryType, startOffset, \ + endOffset, text); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_textAtOffset( \ + long offset, enum IA2TextBoundaryType boundaryType, long* startOffset, \ + long* endOffset, BSTR* text) { \ + return Class::get_textAtOffset(offset, boundaryType, startOffset, \ + endOffset, text); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE removeSelection(long selectionIndex) { \ + return Class::removeSelection(selectionIndex); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE setCaretOffset(long offset) { \ + return Class::setCaretOffset(offset); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE setSelection( \ + long selectionIndex, long startOffset, long endOffset) { \ + return Class::setSelection(selectionIndex, startOffset, endOffset); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_nCharacters(long* nCharacters) { \ + return Class::get_nCharacters(nCharacters); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE scrollSubstringTo( \ + long startIndex, long endIndex, enum IA2ScrollType scrollType) { \ + return Class::scrollSubstringTo(startIndex, endIndex, scrollType); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE scrollSubstringToPoint( \ + long startIndex, long endIndex, enum IA2CoordinateType coordinateType, \ + long x, long y) { \ + return Class::scrollSubstringToPoint(startIndex, endIndex, coordinateType, \ + x, y); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_newText(IA2TextSegment* newText) { \ + return Class::get_newText(newText); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_oldText(IA2TextSegment* oldText) { \ + return Class::get_oldText(oldText); \ + } + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleValue.cpp b/accessible/windows/ia2/ia2AccessibleValue.cpp new file mode 100644 index 0000000000..7c41ba5758 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleValue.cpp @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleValue.h" + +#include "AccessibleValue_i.c" + +#include "AccessibleWrap.h" +#include "Accessible-inl.h" +#include "IUnknownImpl.h" + +#include "mozilla/FloatingPoint.h" + +using namespace mozilla::a11y; + +// IUnknown + +STDMETHODIMP +ia2AccessibleValue::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleValue == iid) { + AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this); + if (valueAcc->HasNumericValue()) { + *ppv = static_cast<IAccessibleValue*>(this); + valueAcc->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; + } + + return E_NOINTERFACE; +} + +// IAccessibleValue + +STDMETHODIMP +ia2AccessibleValue::get_currentValue(VARIANT* aCurrentValue) { + if (!aCurrentValue) return E_INVALIDARG; + + VariantInit(aCurrentValue); + + AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this); + double currentValue; + MOZ_ASSERT(!valueAcc->IsProxy()); + if (valueAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + currentValue = valueAcc->CurValue(); + + if (IsNaN(currentValue)) return S_FALSE; + + aCurrentValue->vt = VT_R8; + aCurrentValue->dblVal = currentValue; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleValue::setCurrentValue(VARIANT aValue) { + if (aValue.vt != VT_R8) return E_INVALIDARG; + + AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this); + MOZ_ASSERT(!valueAcc->IsProxy()); + + if (valueAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + + return valueAcc->SetCurValue(aValue.dblVal) ? S_OK : E_FAIL; +} + +STDMETHODIMP +ia2AccessibleValue::get_maximumValue(VARIANT* aMaximumValue) { + if (!aMaximumValue) return E_INVALIDARG; + + VariantInit(aMaximumValue); + + AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this); + double maximumValue; + MOZ_ASSERT(!valueAcc->IsProxy()); + if (valueAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + maximumValue = valueAcc->MaxValue(); + + if (IsNaN(maximumValue)) return S_FALSE; + + aMaximumValue->vt = VT_R8; + aMaximumValue->dblVal = maximumValue; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleValue::get_minimumValue(VARIANT* aMinimumValue) { + if (!aMinimumValue) return E_INVALIDARG; + + VariantInit(aMinimumValue); + + AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this); + double minimumValue; + MOZ_ASSERT(!valueAcc->IsProxy()); + if (valueAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + minimumValue = valueAcc->MinValue(); + + if (IsNaN(minimumValue)) return S_FALSE; + + aMinimumValue->vt = VT_R8; + aMinimumValue->dblVal = minimumValue; + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleValue.h b/accessible/windows/ia2/ia2AccessibleValue.h new file mode 100644 index 0000000000..e430c60e5a --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleValue.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_VALUE_H +#define _ACCESSIBLE_VALUE_H + +#include "AccessibleValue.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleValue : public IAccessibleValue { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleValue + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_currentValue( + /* [retval][out] */ VARIANT* currentValue); + + virtual HRESULT STDMETHODCALLTYPE setCurrentValue( + /* [in] */ VARIANT value); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_maximumValue( + /* [retval][out] */ VARIANT* maximumValue); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_minimumValue( + /* [retval][out] */ VARIANT* minimumValue); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/moz.build b/accessible/windows/ia2/moz.build new file mode 100644 index 0000000000..7357fe48a8 --- /dev/null +++ b/accessible/windows/ia2/moz.build @@ -0,0 +1,58 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS += [ + "ia2Accessible.h", + "ia2AccessibleAction.h", + "ia2AccessibleComponent.h", + "ia2AccessibleEditableText.h", + "ia2AccessibleHyperlink.h", + "ia2AccessibleHypertext.h", + "ia2AccessibleText.h", + "ia2AccessibleValue.h", +] + +UNIFIED_SOURCES += [ + "ia2Accessible.cpp", + "ia2AccessibleAction.cpp", + "ia2AccessibleComponent.cpp", + "ia2AccessibleEditableText.cpp", + "ia2AccessibleHyperlink.cpp", + "ia2AccessibleHypertext.cpp", + "ia2AccessibleImage.cpp", + "ia2AccessibleRelation.cpp", + "ia2AccessibleText.cpp", + "ia2AccessibleValue.cpp", +] + +# These files cannot be built in unified mode because they both include +# AccessibleTable2_i.c. +SOURCES += [ + "ia2AccessibleTable.cpp", + "ia2AccessibleTableCell.cpp", +] + +LOCAL_INCLUDES += [ + "/accessible/base", + "/accessible/generic", + "/accessible/html", + "/accessible/windows", + "/accessible/windows/msaa", + "/accessible/xpcom", + "/accessible/xul", +] + +FINAL_LIBRARY = "xul" + +# The Windows MIDL code generator creates things like: +# +# #endif !_MIDL_USE_GUIDDEF_ +# +# which clang-cl complains about. MSVC doesn't, so turn this warning off. +if CONFIG["CC_TYPE"] == "clang-cl": + CXXFLAGS += ["-Wno-extra-tokens"] + +include("/ipc/chromium/chromium-config.mozbuild") |