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