diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /accessible/windows/ia2 | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'accessible/windows/ia2')
29 files changed, 4191 insertions, 0 deletions
diff --git a/accessible/windows/ia2/ia2Accessible.cpp b/accessible/windows/ia2/ia2Accessible.cpp new file mode 100644 index 0000000000..2092730932 --- /dev/null +++ b/accessible/windows/ia2/ia2Accessible.cpp @@ -0,0 +1,563 @@ +/* -*- 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 "AccessibleRole.h" +#include "AccessibleStates.h" + +#include "AccAttributes.h" +#include "Compatibility.h" +#include "ia2AccessibleRelation.h" +#include "IUnknownImpl.h" +#include "nsCoreUtils.h" +#include "nsIAccessibleTypes.h" +#include "mozilla/a11y/PDocAccessible.h" +#include "Relation.h" +#include "TextRange-inl.h" +#include "nsAccessibilityService.h" + +#include "mozilla/PresShell.h" +#include "nsISimpleEnumerator.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +//////////////////////////////////////////////////////////////////////////////// +// ia2Accessible +//////////////////////////////////////////////////////////////////////////////// + +STDMETHODIMP +ia2Accessible::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + // NOTE: If any new versions of IAccessible2 are added here, they should + // also be added to the IA2 Handler in + // /accessible/ipc/win/handler/AccessibleHandler.cpp + + if (IID_IAccessible2_2 == iid) { + *ppv = static_cast<IAccessible2_2*>(this); + } else if (IID_IAccessible2 == iid) { + *ppv = static_cast<IAccessible2*>(this); + } + + if (*ppv) { + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +AccessibleWrap* ia2Accessible::LocalAcc() { + return static_cast<MsaaAccessible*>(this)->LocalAcc(); +} + +Accessible* ia2Accessible::Acc() { + return static_cast<MsaaAccessible*>(this)->Acc(); +} + +//////////////////////////////////////////////////////////////////////////////// +// IAccessible2 + +STDMETHODIMP +ia2Accessible::get_nRelations(long* aNRelations) { + if (!aNRelations) return E_INVALIDARG; + *aNRelations = 0; + + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { + if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; + + Relation rel = acc->RelationByType(sRelationTypePairs[idx].first); + if (rel.Next()) (*aNRelations)++; + } + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_relation(long aRelationIndex, + IAccessibleRelation** aRelation) { + if (!aRelation || aRelationIndex < 0) return E_INVALIDARG; + *aRelation = nullptr; + + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + + long relIdx = 0; + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { + if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; + + RelationType relationType = sRelationTypePairs[idx].first; + Relation rel = acc->RelationByType(relationType); + RefPtr<ia2AccessibleRelation> ia2Relation = + new ia2AccessibleRelation(relationType, &rel); + if (ia2Relation->HasTargets()) { + if (relIdx == aRelationIndex) { + ia2Relation.forget(aRelation); + return S_OK; + } + + relIdx++; + } + } + + return E_INVALIDARG; +} + +STDMETHODIMP +ia2Accessible::get_relations(long aMaxRelations, + IAccessibleRelation** aRelation, + long* aNRelations) { + if (!aRelation || !aNRelations || aMaxRelations <= 0) return E_INVALIDARG; + *aNRelations = 0; + + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + + for (uint32_t idx = 0; + idx < ArrayLength(sRelationTypePairs) && *aNRelations < aMaxRelations; + idx++) { + if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; + + RelationType relationType = sRelationTypePairs[idx].first; + Relation rel = acc->RelationByType(relationType); + RefPtr<ia2AccessibleRelation> ia2Rel = + new ia2AccessibleRelation(relationType, &rel); + if (ia2Rel->HasTargets()) { + ia2Rel.forget(aRelation + (*aNRelations)); + (*aNRelations)++; + } + } + return S_OK; +} + +STDMETHODIMP +ia2Accessible::role(long* aRole) { + if (!aRole) return E_INVALIDARG; + *aRole = 0; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + +#define ROLE(_geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \ + msaaRole, ia2Role, androidClass, nameRule) \ + case roles::_geckoRole: \ + *aRole = ia2Role; \ + break; + + a11y::role geckoRole; + geckoRole = acc->Role(); + switch (geckoRole) { +#include "RoleMap.h" + default: + MOZ_CRASH("Unknown role."); + } + +#undef ROLE + + // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call + // the IA2 role a ROLE_OUTLINEITEM. + if (geckoRole == roles::ROW) { + Accessible* xpParent = acc->Parent(); + if (xpParent && xpParent->Role() == roles::TREE_TABLE) + *aRole = ROLE_SYSTEM_OUTLINEITEM; + } + + return S_OK; +} + +// XXX Use MOZ_CAN_RUN_SCRIPT_BOUNDARY for now due to bug 1543294. +MOZ_CAN_RUN_SCRIPT_BOUNDARY STDMETHODIMP +ia2Accessible::scrollTo(enum IA2ScrollType aScrollType) { + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + + acc->ScrollTo(aScrollType); + return S_OK; +} + +STDMETHODIMP +ia2Accessible::scrollToPoint(enum IA2CoordinateType aCoordType, long aX, + long aY) { + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + + uint32_t geckoCoordType = + (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) + ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE + : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + + acc->ScrollToPoint(geckoCoordType, aX, aY); + + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_groupPosition(long* aGroupLevel, long* aSimilarItemsInGroup, + long* aPositionInGroup) { + if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup) + return E_INVALIDARG; + + *aGroupLevel = 0; + *aSimilarItemsInGroup = 0; + *aPositionInGroup = 0; + + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + + GroupPos groupPos = acc->GroupPosition(); + + // Group information for accessibles having level only (like html headings + // elements) isn't exposed by this method. AT should look for 'level' object + // attribute. + if (!groupPos.setSize && !groupPos.posInSet) return S_FALSE; + + *aGroupLevel = groupPos.level; + *aSimilarItemsInGroup = groupPos.setSize; + *aPositionInGroup = groupPos.posInSet; + + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_states(AccessibleStates* aStates) { + if (!aStates) return E_INVALIDARG; + *aStates = 0; + + // XXX: bug 344674 should come with better approach that we have here. + + Accessible* acc = Acc(); + if (!acc) { + *aStates = IA2_STATE_DEFUNCT; + return S_OK; + } + + uint64_t state; + state = acc->State(); + + if (state & states::INVALID) *aStates |= IA2_STATE_INVALID_ENTRY; + if (state & states::REQUIRED) *aStates |= IA2_STATE_REQUIRED; + + // The following IA2 states are not supported by Gecko + // IA2_STATE_ARMED + // IA2_STATE_MANAGES_DESCENDANTS + // IA2_STATE_ICONIFIED + // IA2_STATE_INVALID // This is not a state, it is the absence of a state + + if (state & states::ACTIVE) *aStates |= IA2_STATE_ACTIVE; + if (state & states::DEFUNCT) *aStates |= IA2_STATE_DEFUNCT; + if (state & states::EDITABLE) *aStates |= IA2_STATE_EDITABLE; + if (state & states::HORIZONTAL) *aStates |= IA2_STATE_HORIZONTAL; + if (state & states::MODAL) *aStates |= IA2_STATE_MODAL; + if (state & states::MULTI_LINE) *aStates |= IA2_STATE_MULTI_LINE; + if (state & states::OPAQUE1) *aStates |= IA2_STATE_OPAQUE; + if (state & states::SELECTABLE_TEXT) *aStates |= IA2_STATE_SELECTABLE_TEXT; + if (state & states::SINGLE_LINE) *aStates |= IA2_STATE_SINGLE_LINE; + if (state & states::STALE) *aStates |= IA2_STATE_STALE; + if (state & states::SUPPORTS_AUTOCOMPLETION) + *aStates |= IA2_STATE_SUPPORTS_AUTOCOMPLETION; + if (state & states::TRANSIENT) *aStates |= IA2_STATE_TRANSIENT; + if (state & states::VERTICAL) *aStates |= IA2_STATE_VERTICAL; + if (state & states::CHECKED) *aStates |= IA2_STATE_CHECKABLE; + if (state & states::PINNED) *aStates |= IA2_STATE_PINNED; + + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_extendedRole(BSTR* aExtendedRole) { + if (!aExtendedRole) return E_INVALIDARG; + + *aExtendedRole = nullptr; + return E_NOTIMPL; +} + +STDMETHODIMP +ia2Accessible::get_localizedExtendedRole(BSTR* aLocalizedExtendedRole) { + if (!aLocalizedExtendedRole) return E_INVALIDARG; + + *aLocalizedExtendedRole = nullptr; + return E_NOTIMPL; +} + +STDMETHODIMP +ia2Accessible::get_nExtendedStates(long* aNExtendedStates) { + if (!aNExtendedStates) return E_INVALIDARG; + + *aNExtendedStates = 0; + return E_NOTIMPL; +} + +STDMETHODIMP +ia2Accessible::get_extendedStates(long aMaxExtendedStates, + BSTR** aExtendedStates, + long* aNExtendedStates) { + if (!aExtendedStates || !aNExtendedStates) return E_INVALIDARG; + + *aExtendedStates = nullptr; + *aNExtendedStates = 0; + return E_NOTIMPL; +} + +STDMETHODIMP +ia2Accessible::get_localizedExtendedStates(long aMaxLocalizedExtendedStates, + BSTR** aLocalizedExtendedStates, + long* aNLocalizedExtendedStates) { + if (!aLocalizedExtendedStates || !aNLocalizedExtendedStates) + return E_INVALIDARG; + + *aLocalizedExtendedStates = nullptr; + *aNLocalizedExtendedStates = 0; + return E_NOTIMPL; +} + +STDMETHODIMP +ia2Accessible::get_uniqueID(long* aUniqueID) { + if (!aUniqueID) return E_INVALIDARG; + + Accessible* acc = Acc(); + *aUniqueID = MsaaAccessible::GetChildIDFor(acc); + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_windowHandle(HWND* aWindowHandle) { + if (!aWindowHandle) return E_INVALIDARG; + *aWindowHandle = 0; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + *aWindowHandle = MsaaAccessible::GetHWNDFor(acc); + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_indexInParent(long* aIndexInParent) { + if (!aIndexInParent) return E_INVALIDARG; + *aIndexInParent = -1; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + *aIndexInParent = acc->IndexInParent(); + + if (*aIndexInParent == -1) return S_FALSE; + + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_locale(IA2Locale* aLocale) { + if (!aLocale) return E_INVALIDARG; + + // Language codes consist of a primary code and a possibly empty series of + // subcodes: language-code = primary-code ( "-" subcode )* + // Two-letter primary codes are reserved for [ISO639] language abbreviations. + // Any two-letter subcode is understood to be a [ISO3166] country code. + + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + + nsAutoString lang; + acc->Language(lang); + + // If primary code consists from two letters then expose it as language. + int32_t offset = lang.FindChar('-', 0); + if (offset == -1) { + if (lang.Length() == 2) { + aLocale->language = ::SysAllocString(lang.get()); + return S_OK; + } + } else if (offset == 2) { + aLocale->language = ::SysAllocStringLen(lang.get(), 2); + + // If the first subcode consists from two letters then expose it as + // country. + offset = lang.FindChar('-', 3); + if (offset == -1) { + if (lang.Length() == 5) { + aLocale->country = ::SysAllocString(lang.get() + 3); + return S_OK; + } + } else if (offset == 5) { + aLocale->country = ::SysAllocStringLen(lang.get() + 3, 2); + } + } + + // Expose as a string if primary code or subcode cannot point to language or + // country abbreviations or if there are more than one subcode. + aLocale->variant = ::SysAllocString(lang.get()); + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_attributes(BSTR* aAttributes) { + if (!aAttributes) return E_INVALIDARG; + *aAttributes = nullptr; + + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + + // The format is name:value;name:value; with \ for escaping these + // characters ":;=,\". + RefPtr<AccAttributes> attributes = acc->Attributes(); + return ConvertToIA2Attributes(attributes, aAttributes); +} + +//////////////////////////////////////////////////////////////////////////////// +// IAccessible2_2 + +STDMETHODIMP +ia2Accessible::get_attribute(BSTR name, VARIANT* aAttribute) { + if (!aAttribute) return E_INVALIDARG; + + return E_NOTIMPL; +} + +STDMETHODIMP +ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible, + long* aCaretOffset) { + if (!aAccessible || !aCaretOffset) return E_INVALIDARG; + + *aAccessible = nullptr; + *aCaretOffset = -1; + + if (!Acc()) { + return CO_E_OBJNOTCONNECTED; + } + AccessibleWrap* acc = LocalAcc(); + if (!acc) { + return E_NOTIMPL; // XXX Not supported for RemoteAccessible yet. + } + + int32_t caretOffset = -1; + LocalAccessible* accWithCaret = + SelectionMgr()->AccessibleWithCaret(&caretOffset); + if (!accWithCaret || acc->Document() != accWithCaret->Document()) + return S_FALSE; + + LocalAccessible* child = accWithCaret; + while (!child->IsDoc() && child != acc) child = child->LocalParent(); + + if (child != acc) return S_FALSE; + + RefPtr<IAccessible2> ia2WithCaret; + accWithCaret->GetNativeInterface(getter_AddRefs(ia2WithCaret)); + ia2WithCaret.forget(aAccessible); + *aCaretOffset = caretOffset; + return S_OK; +} + +STDMETHODIMP +ia2Accessible::get_relationTargetsOfType(BSTR aType, long aMaxTargets, + IUnknown*** aTargets, + long* aNTargets) { + if (!aTargets || !aNTargets || aMaxTargets < 0) return E_INVALIDARG; + *aNTargets = 0; + + Maybe<RelationType> relationType; + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { + if (wcscmp(aType, sRelationTypePairs[idx].second) == 0) { + relationType.emplace(sRelationTypePairs[idx].first); + break; + } + } + if (!relationType) return E_INVALIDARG; + + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + + nsTArray<Accessible*> targets; + Relation rel = acc->RelationByType(*relationType); + Accessible* target = nullptr; + while ( + (target = rel.Next()) && + (aMaxTargets == 0 || static_cast<long>(targets.Length()) < aMaxTargets)) { + targets.AppendElement(target); + } + + *aNTargets = targets.Length(); + *aTargets = + static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) * *aNTargets)); + if (!*aTargets) return E_OUTOFMEMORY; + + for (int32_t i = 0; i < *aNTargets; i++) { + (*aTargets)[i] = MsaaAccessible::NativeAccessible(targets[i]); + } + + return S_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// Helpers + +static inline void EscapeAttributeChars(nsString& aStr) { + int32_t offset = 0; + static const char16_t kCharsToEscape[] = u":;=,\\"; + while ((offset = aStr.FindCharInSet(kCharsToEscape, offset)) != kNotFound) { + aStr.Insert('\\', offset); + offset += 2; + } +} + +HRESULT +ia2Accessible::ConvertToIA2Attributes(AccAttributes* aAttributes, + BSTR* aIA2Attributes) { + *aIA2Attributes = nullptr; + + // The format is name:value;name:value; with \ for escaping these + // characters ":;=,\". + + if (!aAttributes) return S_FALSE; + + nsAutoString strAttrs; + + for (auto iter : *aAttributes) { + nsAutoString name; + iter.NameAsString(name); + EscapeAttributeChars(name); + + nsAutoString value; + iter.ValueAsString(value); + EscapeAttributeChars(value); + + strAttrs.Append(name); + strAttrs.Append(':'); + strAttrs.Append(value); + strAttrs.Append(';'); + } + + if (strAttrs.IsEmpty()) return S_FALSE; + + *aIA2Attributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length()); + return *aIA2Attributes ? S_OK : E_OUTOFMEMORY; +} diff --git a/accessible/windows/ia2/ia2Accessible.h b/accessible/windows/ia2/ia2Accessible.h new file mode 100644 index 0000000000..ba65d9fcf9 --- /dev/null +++ b/accessible/windows/ia2/ia2Accessible.h @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_ia2Accessible_h_ +#define mozilla_a11y_ia2Accessible_h_ + +#include "nsISupports.h" +#include "nsTArray.h" + +#include "Accessible2_2.h" + +namespace mozilla { +namespace a11y { +class Accessible; +class AccAttributes; +class AccessibleWrap; + +class ia2Accessible : public IAccessible2_2 { + 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); + + // Helper method + static HRESULT ConvertToIA2Attributes(AccAttributes* aAttributes, + BSTR* aIA2Attributes); + + private: + AccessibleWrap* LocalAcc(); + Accessible* Acc(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleAction.cpp b/accessible/windows/ia2/ia2AccessibleAction.cpp new file mode 100644 index 0000000000..d89bd79ce1 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleAction.cpp @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleAction.h" + +#include "AccessibleAction_i.c" + +#include "AccessibleWrap.h" +#include "IUnknownImpl.h" + +using namespace mozilla::a11y; + +Accessible* ia2AccessibleAction::Acc() { + return static_cast<MsaaAccessible*>(this)->Acc(); +} + +// IUnknown + +STDMETHODIMP +ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleAction == iid) { + *ppv = static_cast<IAccessibleAction*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +// IAccessibleAction + +STDMETHODIMP +ia2AccessibleAction::nActions(long* aActionCount) { + if (!aActionCount) return E_INVALIDARG; + + *aActionCount = 0; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + *aActionCount = acc->ActionCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleAction::doAction(long aActionIndex) { + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + uint8_t index = static_cast<uint8_t>(aActionIndex); + return acc->DoAction(index) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP +ia2AccessibleAction::get_description(long aActionIndex, BSTR* aDescription) { + if (!aDescription) return E_INVALIDARG; + *aDescription = nullptr; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + nsAutoString description; + uint8_t index = static_cast<uint8_t>(aActionIndex); + acc->ActionDescriptionAt(index, description); + if (description.IsEmpty()) return S_FALSE; + + *aDescription = ::SysAllocStringLen(description.get(), description.Length()); + return *aDescription ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleAction::get_keyBinding(long aActionIndex, long aNumMaxBinding, + BSTR** aKeyBinding, long* aNumBinding) { + if (!aKeyBinding) return E_INVALIDARG; + *aKeyBinding = nullptr; + + if (!aNumBinding) return E_INVALIDARG; + *aNumBinding = 0; + + if (aActionIndex != 0 || aNumMaxBinding < 1) return E_INVALIDARG; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + // Expose KeyboardShortcut if it's not exposed via MSAA accKeyboardShortcut. + LocalAccessible* localAcc = acc->AsLocal(); + if (!localAcc) { + // RemoteAccessibles can't have a KeyboardShortcut. + return S_FALSE; + } + + KeyBinding keyBinding = acc->AccessKey(); + if (keyBinding.IsEmpty()) { + // In this case, KeyboardShortcut will be exposed via MSAA + // accKeyboardShortcut. + return S_FALSE; + } + + // MSAA accKeyboardShortcut will expose AccessKey. + keyBinding = localAcc->KeyboardShortcut(); + if (keyBinding.IsEmpty()) return S_FALSE; + + nsAutoString keyStr; + keyBinding.ToString(keyStr); + + *aKeyBinding = static_cast<BSTR*>(::CoTaskMemAlloc(sizeof(BSTR*))); + if (!*aKeyBinding) return E_OUTOFMEMORY; + + *(aKeyBinding[0]) = ::SysAllocStringLen(keyStr.get(), keyStr.Length()); + if (!*(aKeyBinding[0])) { + ::CoTaskMemFree(*aKeyBinding); + return E_OUTOFMEMORY; + } + + *aNumBinding = 1; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleAction::get_name(long aActionIndex, BSTR* aName) { + if (!aName) return E_INVALIDARG; + + *aName = nullptr; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + nsAutoString name; + uint8_t index = static_cast<uint8_t>(aActionIndex); + acc->ActionNameAt(index, name); + if (name.IsEmpty()) return E_INVALIDARG; + + *aName = ::SysAllocStringLen(name.get(), name.Length()); + return *aName ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleAction::get_localizedName(long aActionIndex, + BSTR* aLocalizedName) { + if (!aLocalizedName) return E_INVALIDARG; + + *aLocalizedName = nullptr; + return E_NOTIMPL; +} diff --git a/accessible/windows/ia2/ia2AccessibleAction.h b/accessible/windows/ia2/ia2AccessibleAction.h new file mode 100644 index 0000000000..ae3749a039 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleAction.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 _ACCESSIBLE_ACTION_H +#define _ACCESSIBLE_ACTION_H + +#include "nsISupports.h" + +#include "mozilla/a11y/Accessible.h" +#include "AccessibleAction.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleAction : public IAccessibleAction { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleAction + virtual HRESULT STDMETHODCALLTYPE nActions( + /* [retval][out] */ long* nActions); + + virtual HRESULT STDMETHODCALLTYPE doAction( + /* [in] */ long actionIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_description( + /* [in] */ long actionIndex, + /* [retval][out] */ BSTR* description); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_keyBinding( + /* [in] */ long actionIndex, + /* [in] */ long nMaxBinding, + /* [length_is][length_is][size_is][size_is][out] */ BSTR** keyBinding, + /* [retval][out] */ long* nBinding); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_name( + /* [in] */ long actionIndex, + /* [retval][out] */ BSTR* name); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedName( + /* [in] */ long actionIndex, + /* [retval][out] */ BSTR* localizedName); + + private: + Accessible* Acc(); +}; + +} // namespace a11y +} // namespace mozilla + +#define FORWARD_IACCESSIBLEACTION(Class) \ + virtual HRESULT STDMETHODCALLTYPE nActions(long* nActions) { \ + return Class::nActions(nActions); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE doAction(long actionIndex) { \ + return Class::doAction(actionIndex); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_description(long actionIndex, \ + BSTR* description) { \ + return Class::get_description(actionIndex, description); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_keyBinding( \ + long actionIndex, long nMaxBinding, BSTR** keyBinding, long* nBinding) { \ + return Class::get_keyBinding(actionIndex, nMaxBinding, keyBinding, \ + nBinding); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_name(long actionIndex, BSTR* name) { \ + return Class::get_name(actionIndex, name); \ + } \ + \ + virtual HRESULT STDMETHODCALLTYPE get_localizedName(long actionIndex, \ + BSTR* localizedName) { \ + return Class::get_localizedName(actionIndex, localizedName); \ + } + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleApplication.cpp b/accessible/windows/ia2/ia2AccessibleApplication.cpp new file mode 100644 index 0000000000..7844e97074 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleApplication.cpp @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=4:tabstop=4: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleApplication.h" + +#include "AccessibleApplication_i.c" +#include "ApplicationAccessibleWrap.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +ApplicationAccessible* ia2AccessibleApplication::AppAcc() { + return static_cast<ApplicationAccessible*>(LocalAcc()); +} + +//////////////////////////////////////////////////////////////////////////////// +// IUnknown + +IMPL_IUNKNOWN_QUERY_HEAD(ia2AccessibleApplication) +IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleApplication) +IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(MsaaAccessible) + +//////////////////////////////////////////////////////////////////////////////// +// IAccessibleApplication + +STDMETHODIMP +ia2AccessibleApplication::get_appName(BSTR* aName) { + if (!aName) return E_INVALIDARG; + + *aName = nullptr; + + ApplicationAccessible* appAcc = AppAcc(); + if (!appAcc) return CO_E_OBJNOTCONNECTED; + + nsAutoString name; + appAcc->AppName(name); + if (name.IsEmpty()) return S_FALSE; + + *aName = ::SysAllocStringLen(name.get(), name.Length()); + return *aName ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleApplication::get_appVersion(BSTR* aVersion) { + if (!aVersion) return E_INVALIDARG; + + *aVersion = nullptr; + + ApplicationAccessible* appAcc = AppAcc(); + if (!appAcc) return CO_E_OBJNOTCONNECTED; + + nsAutoString version; + appAcc->AppVersion(version); + if (version.IsEmpty()) return S_FALSE; + + *aVersion = ::SysAllocStringLen(version.get(), version.Length()); + return *aVersion ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleApplication::get_toolkitName(BSTR* aName) { + if (!aName) return E_INVALIDARG; + + ApplicationAccessible* appAcc = AppAcc(); + if (!appAcc) return CO_E_OBJNOTCONNECTED; + + nsAutoString name; + appAcc->PlatformName(name); + if (name.IsEmpty()) return S_FALSE; + + *aName = ::SysAllocStringLen(name.get(), name.Length()); + return *aName ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleApplication::get_toolkitVersion(BSTR* aVersion) { + if (!aVersion) return E_INVALIDARG; + + *aVersion = nullptr; + + ApplicationAccessible* appAcc = AppAcc(); + if (!appAcc) return CO_E_OBJNOTCONNECTED; + + nsAutoString version; + appAcc->PlatformVersion(version); + if (version.IsEmpty()) return S_FALSE; + + *aVersion = ::SysAllocStringLen(version.get(), version.Length()); + return *aVersion ? S_OK : E_OUTOFMEMORY; +} diff --git a/accessible/windows/ia2/ia2AccessibleApplication.h b/accessible/windows/ia2/ia2AccessibleApplication.h new file mode 100644 index 0000000000..283dc38471 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleApplication.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef IA2_ACCESSIBLE_APPLICATION_H_ +#define IA2_ACCESSIBLE_APPLICATION_H_ + +#include "AccessibleApplication.h" +#include "IUnknownImpl.h" +#include "MsaaAccessible.h" + +namespace mozilla { +namespace a11y { +class ApplicationAccessible; + +class ia2AccessibleApplication : public IAccessibleApplication, + public MsaaAccessible { + public: + // IUnknown + DECL_IUNKNOWN_INHERITED + IMPL_IUNKNOWN_REFCOUNTING_INHERITED(MsaaAccessible) + + // IAccessibleApplication + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_appName( + /* [retval][out] */ BSTR* name); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_appVersion( + /* [retval][out] */ BSTR* version); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_toolkitName( + /* [retval][out] */ BSTR* name); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_toolkitVersion( + /* [retval][out] */ BSTR* version); + + protected: + using MsaaAccessible::MsaaAccessible; + + private: + ApplicationAccessible* AppAcc(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleComponent.cpp b/accessible/windows/ia2/ia2AccessibleComponent.cpp new file mode 100644 index 0000000000..9c22a66cad --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleComponent.cpp @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleComponent.h" + +#include "AccessibleComponent_i.c" + +#include "AccessibleWrap.h" +#include "States.h" +#include "IUnknownImpl.h" + +#include "nsIFrame.h" + +using namespace mozilla::a11y; + +AccessibleWrap* ia2AccessibleComponent::LocalAcc() { + return static_cast<MsaaAccessible*>(this)->LocalAcc(); +} + +// IUnknown + +STDMETHODIMP +ia2AccessibleComponent::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleComponent == iid) { + *ppv = static_cast<IAccessibleComponent*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +// IAccessibleComponent + +STDMETHODIMP +ia2AccessibleComponent::get_locationInParent(long* aX, long* aY) { + if (!aX || !aY) return E_INVALIDARG; + + *aX = 0; + *aY = 0; + + AccessibleWrap* acc = LocalAcc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + // If the object is not on any screen the returned position is (0,0). + uint64_t state = acc->State(); + if (state & states::INVISIBLE) return S_OK; + + LayoutDeviceIntRect rect = acc->Bounds(); + + // The coordinates of the returned position are relative to this object's + // parent or relative to the screen on which this object is rendered if it + // has no parent. + if (!acc->LocalParent()) { + *aX = rect.X(); + *aY = rect.Y(); + return S_OK; + } + + // The coordinates of the bounding box are given relative to the parent's + // coordinate system. + LayoutDeviceIntRect parentRect = acc->LocalParent()->Bounds(); + *aX = rect.X() - parentRect.X(); + *aY = rect.Y() - parentRect.Y(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleComponent::get_foreground(IA2Color* aForeground) { + if (!aForeground) return E_INVALIDARG; + + *aForeground = 0; + + AccessibleWrap* acc = LocalAcc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + nsIFrame* frame = acc->GetFrame(); + if (frame) *aForeground = frame->StyleText()->mColor.ToColor(); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleComponent::get_background(IA2Color* aBackground) { + if (!aBackground) return E_INVALIDARG; + + *aBackground = 0; + + AccessibleWrap* acc = LocalAcc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + nsIFrame* frame = acc->GetFrame(); + if (frame) { + *aBackground = frame->StyleBackground()->BackgroundColor(frame); + } + + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleComponent.h b/accessible/windows/ia2/ia2AccessibleComponent.h new file mode 100644 index 0000000000..507bbbd628 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleComponent.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef IA2_ACCESSIBLE_COMPONENT_H_ +#define IA2_ACCESSIBLE_COMPONENT_H_ + +#include "AccessibleComponent.h" + +namespace mozilla { +namespace a11y { +class AccessibleWrap; + +class ia2AccessibleComponent : public IAccessibleComponent { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleComponent + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_locationInParent( + /* [out] */ long* x, + /* [retval][out] */ long* y); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_foreground( + /* [retval][out] */ IA2Color* foreground); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_background( + /* [retval][out] */ IA2Color* background); + + private: + AccessibleWrap* LocalAcc(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleEditableText.cpp b/accessible/windows/ia2/ia2AccessibleEditableText.cpp new file mode 100644 index 0000000000..4e96736396 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleEditableText.cpp @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleEditableText.h" +#include "ia2AccessibleHypertext.h" + +#include "AccessibleEditableText_i.c" +#include "mozilla/a11y/HyperTextAccessibleBase.h" + +#include "nsCOMPtr.h" +#include "nsString.h" + +using namespace mozilla::a11y; + +HyperTextAccessibleBase* ia2AccessibleEditableText::TextAcc() { + auto hyp = static_cast<ia2AccessibleHypertext*>(this); + Accessible* acc = hyp->Acc(); + return acc ? acc->AsHyperTextBase() : nullptr; +} + +// IAccessibleEditableText + +STDMETHODIMP +ia2AccessibleEditableText::copyText(long aStartOffset, long aEndOffset) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG; + + textAcc->CopyText(aStartOffset, aEndOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::deleteText(long aStartOffset, long aEndOffset) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG; + + textAcc->DeleteText(aStartOffset, aEndOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::insertText(long aOffset, BSTR* aText) { + uint32_t length = ::SysStringLen(*aText); + nsAutoString text(*aText, length); + + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + textAcc->InsertText(text, aOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::cutText(long aStartOffset, long aEndOffset) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG; + + textAcc->CutText(aStartOffset, aEndOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::pasteText(long aOffset) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + textAcc->PasteText(aOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::replaceText(long aStartOffset, long aEndOffset, + BSTR* aText) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG; + + textAcc->DeleteText(aStartOffset, aEndOffset); + + uint32_t length = ::SysStringLen(*aText); + nsAutoString text(*aText, length); + textAcc->InsertText(text, aStartOffset); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleEditableText::setAttributes(long aStartOffset, long aEndOffset, + BSTR* aAttributes) { + return E_NOTIMPL; +} diff --git a/accessible/windows/ia2/ia2AccessibleEditableText.h b/accessible/windows/ia2/ia2AccessibleEditableText.h new file mode 100644 index 0000000000..0b018485d9 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleEditableText.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_EDITABLETEXT_H +#define _ACCESSIBLE_EDITABLETEXT_H + +#include "nsISupports.h" + +#include "AccessibleEditableText.h" + +namespace mozilla { +namespace a11y { +class HyperTextAccessibleBase; + +class ia2AccessibleEditableText : public IAccessibleEditableText { + public: + // IAccessibleEditableText + virtual HRESULT STDMETHODCALLTYPE copyText( + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + virtual HRESULT STDMETHODCALLTYPE deleteText( + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + virtual HRESULT STDMETHODCALLTYPE insertText( + /* [in] */ long offset, + /* [in] */ BSTR* text); + + virtual HRESULT STDMETHODCALLTYPE cutText( + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual HRESULT STDMETHODCALLTYPE pasteText( + /* [in] */ long offset); + + virtual HRESULT STDMETHODCALLTYPE replaceText( + /* [in] */ long startOffset, + /* [in] */ long endOffset, + /* [in] */ BSTR* text); + + virtual HRESULT STDMETHODCALLTYPE setAttributes( + /* [in] */ long startOffset, + /* [in] */ long endOffset, + /* [in] */ BSTR* attributes); + + private: + HyperTextAccessibleBase* TextAcc(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleHyperlink.cpp b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp new file mode 100644 index 0000000000..9d71cfb411 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AccessibleHyperlink.h" +#include "AccessibleHyperlink_i.c" + +#include "AccessibleWrap.h" +#include "IUnknownImpl.h" +#include "nsIURI.h" + +using namespace mozilla::a11y; + +Accessible* ia2AccessibleHyperlink::Acc() { + return static_cast<MsaaAccessible*>(this)->Acc(); +} + +AccessibleWrap* ia2AccessibleHyperlink::LocalAcc() { + return static_cast<MsaaAccessible*>(this)->LocalAcc(); +} + +// IUnknown + +STDMETHODIMP +ia2AccessibleHyperlink::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleHyperlink == iid) { + Accessible* acc = Acc(); + if (!acc || !acc->IsLink()) { + return E_NOINTERFACE; + } + + *ppv = static_cast<IAccessibleHyperlink*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return ia2AccessibleAction::QueryInterface(iid, ppv); +} + +// IAccessibleHyperlink + +STDMETHODIMP +ia2AccessibleHyperlink::get_anchor(long aIndex, VARIANT* aAnchor) { + if (!aAnchor) return E_INVALIDARG; + + VariantInit(aAnchor); + + Accessible* thisObj = Acc(); + if (!thisObj) { + return CO_E_OBJNOTCONNECTED; + } + + if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount())) + return E_INVALIDARG; + + if (!thisObj->IsLink()) return S_FALSE; + + Accessible* anchor = thisObj->AnchorAt(aIndex); + if (!anchor) return S_FALSE; + + RefPtr<IAccessible> result = MsaaAccessible::GetFrom(anchor); + result.forget(&aAnchor->punkVal); + aAnchor->vt = VT_UNKNOWN; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHyperlink::get_anchorTarget(long aIndex, VARIANT* aAnchorTarget) { + if (!aAnchorTarget) { + return E_INVALIDARG; + } + + VariantInit(aAnchorTarget); + + Accessible* thisObj = Acc(); + if (!thisObj) { + return CO_E_OBJNOTCONNECTED; + } + nsAutoCString uriStr; + + if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount())) { + return E_INVALIDARG; + } + + if (!thisObj->IsLink()) { + return S_FALSE; + } + + nsCOMPtr<nsIURI> uri = thisObj->AnchorURIAt(aIndex); + if (!uri) { + return S_FALSE; + } + + nsresult rv = uri->GetSpec(uriStr); + if (NS_FAILED(rv)) { + return GetHRESULT(rv); + } + + nsAutoString stringURI; + AppendUTF8toUTF16(uriStr, stringURI); + + aAnchorTarget->vt = VT_BSTR; + aAnchorTarget->bstrVal = + ::SysAllocStringLen(stringURI.get(), stringURI.Length()); + return aAnchorTarget->bstrVal ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleHyperlink::get_startIndex(long* aIndex) { + if (!aIndex) return E_INVALIDARG; + + *aIndex = 0; + + Accessible* thisObj = Acc(); + if (!thisObj) { + return CO_E_OBJNOTCONNECTED; + } + + if (!thisObj->IsLink()) return S_FALSE; + + *aIndex = thisObj->StartOffset(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHyperlink::get_endIndex(long* aIndex) { + if (!aIndex) return E_INVALIDARG; + + *aIndex = 0; + + Accessible* thisObj = Acc(); + if (!thisObj) { + return CO_E_OBJNOTCONNECTED; + } + + if (!thisObj->IsLink()) return S_FALSE; + + *aIndex = thisObj->EndOffset(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHyperlink::get_valid(boolean* aValid) { + if (!aValid) return E_INVALIDARG; + + *aValid = false; + + Accessible* thisObj = Acc(); + if (!thisObj) { + return CO_E_OBJNOTCONNECTED; + } + + if (!thisObj->IsLink()) return S_FALSE; + + *aValid = thisObj->IsLinkValid(); + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleHyperlink.h b/accessible/windows/ia2/ia2AccessibleHyperlink.h new file mode 100644 index 0000000000..e7a2c5a0e2 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleHyperlink.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_HYPERLINK_H +#define _ACCESSIBLE_HYPERLINK_H + +#include "nsISupports.h" + +#include "ia2AccessibleAction.h" +#include "AccessibleHyperlink.h" + +namespace mozilla { +namespace a11y { +class Accessible; +class AccessibleWrap; + +class ia2AccessibleHyperlink : public ia2AccessibleAction, + public IAccessibleHyperlink { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleAction + FORWARD_IACCESSIBLEACTION(ia2AccessibleAction) + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_anchor( + /* [in] */ long index, + /* [retval][out] */ VARIANT* anchor); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_anchorTarget( + /* [in] */ long index, + /* [retval][out] */ VARIANT* anchorTarget); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_startIndex( + /* [retval][out] */ long* index); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_endIndex( + /* [retval][out] */ long* index); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_valid( + /* [retval][out] */ boolean* valid); + + private: + Accessible* Acc(); + AccessibleWrap* LocalAcc(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleHypertext.cpp b/accessible/windows/ia2/ia2AccessibleHypertext.cpp new file mode 100644 index 0000000000..cc8c0cd321 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleHypertext.cpp @@ -0,0 +1,142 @@ +/* -*- 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 "AccessibleHypertext2_i.c" + +#include "mozilla/a11y/HyperTextAccessibleBase.h" + +#include "IUnknownImpl.h" + +using namespace mozilla::a11y; + +HyperTextAccessibleBase* ia2AccessibleHypertext::TextAcc() { + Accessible* acc = Acc(); + return acc ? acc->AsHyperTextBase() : nullptr; +} + +// IUnknown +STDMETHODIMP +ia2AccessibleHypertext::QueryInterface(REFIID aIID, void** aInstancePtr) { + if (!aInstancePtr) return E_FAIL; + + *aInstancePtr = nullptr; + + Accessible* acc = Acc(); + if (acc && acc->IsTextRole()) { + if (aIID == IID_IAccessibleText) { + *aInstancePtr = + static_cast<IAccessibleText*>(static_cast<ia2AccessibleText*>(this)); + } else if (aIID == IID_IAccessibleHypertext) { + *aInstancePtr = static_cast<IAccessibleHypertext*>(this); + } else if (aIID == IID_IAccessibleHypertext2) { + *aInstancePtr = static_cast<IAccessibleHypertext2*>(this); + } else if (aIID == IID_IAccessibleEditableText) { + *aInstancePtr = static_cast<IAccessibleEditableText*>(this); + } else if (aIID == IID_IAccessibleTextSelectionContainer) { + *aInstancePtr = static_cast<IAccessibleTextSelectionContainer*>(this); + } + + if (*aInstancePtr) { + AddRef(); + return S_OK; + } + } + + return MsaaAccessible::QueryInterface(aIID, aInstancePtr); +} + +// IAccessibleHypertext + +STDMETHODIMP +ia2AccessibleHypertext::get_nHyperlinks(long* aHyperlinkCount) { + if (!aHyperlinkCount) return E_INVALIDARG; + + *aHyperlinkCount = 0; + + HyperTextAccessibleBase* hyperText = TextAcc(); + if (!hyperText) return CO_E_OBJNOTCONNECTED; + + *aHyperlinkCount = hyperText->LinkCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHypertext::get_hyperlink(long aLinkIndex, + IAccessibleHyperlink** aHyperlink) { + if (!aHyperlink) return E_INVALIDARG; + + *aHyperlink = nullptr; + + HyperTextAccessibleBase* hyperText = TextAcc(); + if (!hyperText) { + return CO_E_OBJNOTCONNECTED; + } + + Accessible* hyperLink = hyperText->LinkAt(aLinkIndex); + + if (!hyperLink) return E_FAIL; + + RefPtr<IAccessibleHyperlink> result = MsaaAccessible::GetFrom(hyperLink); + result.forget(aHyperlink); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHypertext::get_hyperlinkIndex(long aCharIndex, + long* aHyperlinkIndex) { + if (!aHyperlinkIndex) return E_INVALIDARG; + + *aHyperlinkIndex = 0; + + HyperTextAccessibleBase* hyperAcc = TextAcc(); + if (!hyperAcc) return CO_E_OBJNOTCONNECTED; + + *aHyperlinkIndex = hyperAcc->LinkIndexAtOffset(aCharIndex); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleHypertext::get_hyperlinks(IAccessibleHyperlink*** aHyperlinks, + long* aNHyperlinks) { + if (!aHyperlinks || !aNHyperlinks) { + return E_INVALIDARG; + } + + *aHyperlinks = nullptr; + *aNHyperlinks = 0; + + HyperTextAccessibleBase* hyperText = TextAcc(); + if (!hyperText) { + return CO_E_OBJNOTCONNECTED; + } + + uint32_t count = hyperText->LinkCount(); + *aNHyperlinks = count; + + if (count == 0) { + *aHyperlinks = nullptr; + return S_FALSE; + } + + *aHyperlinks = static_cast<IAccessibleHyperlink**>( + ::CoTaskMemAlloc(sizeof(IAccessibleHyperlink*) * count)); + if (!*aHyperlinks) { + return E_OUTOFMEMORY; + } + + for (uint32_t i = 0; i < count; ++i) { + Accessible* hyperLink = hyperText->LinkAt(i); + MOZ_ASSERT(hyperLink); + RefPtr<IAccessibleHyperlink> iaHyper = MsaaAccessible::GetFrom(hyperLink); + iaHyper.forget(&(*aHyperlinks)[i]); + } + + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleHypertext.h b/accessible/windows/ia2/ia2AccessibleHypertext.h new file mode 100644 index 0000000000..7e99169e2c --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleHypertext.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_HYPERTEXT_H +#define _ACCESSIBLE_HYPERTEXT_H + +#include "nsISupports.h" + +#include "ia2AccessibleEditableText.h" +#include "ia2AccessibleText.h" +#include "ia2AccessibleTextSelectionContainer.h" +#include "AccessibleHypertext2.h" +#include "IUnknownImpl.h" +#include "MsaaAccessible.h" + +namespace mozilla { +namespace a11y { +class HyperTextAccessibleBase; + +class ia2AccessibleHypertext : public ia2AccessibleText, + public IAccessibleHypertext2, + public ia2AccessibleEditableText, + public ia2AccessibleTextSelectionContainer, + public MsaaAccessible { + public: + // IUnknown + DECL_IUNKNOWN_INHERITED + IMPL_IUNKNOWN_REFCOUNTING_INHERITED(MsaaAccessible) + + // IAccessible2 + // We indirectly inherit IAccessible2, which has a get_attributes method, + // but IAccessibleText also has a get_attributes method with a different + // signature. We want both. + using MsaaAccessible::get_attributes; + + // IAccessibleText + FORWARD_IACCESSIBLETEXT(ia2AccessibleText) + + // IAccessibleHypertext + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nHyperlinks( + /* [retval][out] */ long* hyperlinkCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlink( + /* [in] */ long index, + /* [retval][out] */ IAccessibleHyperlink** hyperlink); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlinkIndex( + /* [in] */ long charIndex, + /* [retval][out] */ long* hyperlinkIndex); + + // IAccessibleHypertext2 + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlinks( + /* [out, size_is(,*nHyperlinks)] */ IAccessibleHyperlink*** hyperlinks, + /* [out, retval] */ long* nHyperlinks); + + protected: + using MsaaAccessible::MsaaAccessible; + + private: + HyperTextAccessibleBase* TextAcc(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleImage.cpp b/accessible/windows/ia2/ia2AccessibleImage.cpp new file mode 100644 index 0000000000..529269b566 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleImage.cpp @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleImage.h" + +#include "AccessibleImage_i.c" + +#include "ImageAccessible.h" +#include "IUnknownImpl.h" +#include "nsIAccessibleTypes.h" + +#include "nsString.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +// IUnknown +IMPL_IUNKNOWN_QUERY_HEAD(ia2AccessibleImage) +IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleImage) +IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(MsaaAccessible) + +// IAccessibleImage + +STDMETHODIMP +ia2AccessibleImage::get_description(BSTR* aDescription) { + if (!aDescription) return E_INVALIDARG; + + *aDescription = nullptr; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + nsAutoString description; + acc->Name(description); + if (description.IsEmpty()) return S_FALSE; + + *aDescription = ::SysAllocStringLen(description.get(), description.Length()); + return *aDescription ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleImage::get_imagePosition(enum IA2CoordinateType aCoordType, + long* aX, long* aY) { + if (!aX || !aY) return E_INVALIDARG; + + *aX = 0; + *aY = 0; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + uint32_t geckoCoordType = + (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) + ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE + : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + + LayoutDeviceIntPoint pos = acc->Position(geckoCoordType); + *aX = pos.x; + *aY = pos.y; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleImage::get_imageSize(long* aHeight, long* aWidth) { + if (!aHeight || !aWidth) return E_INVALIDARG; + + *aHeight = 0; + *aWidth = 0; + + Accessible* acc = Acc(); + if (!acc) return CO_E_OBJNOTCONNECTED; + + LayoutDeviceIntSize size = acc->Size(); + *aHeight = size.width; + *aWidth = size.height; + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleImage.h b/accessible/windows/ia2/ia2AccessibleImage.h new file mode 100644 index 0000000000..6302130b3a --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleImage.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_IMAGE_H +#define _ACCESSIBLE_IMAGE_H + +#include "AccessibleImage.h" +#include "IUnknownImpl.h" +#include "MsaaAccessible.h" + +namespace mozilla { +namespace a11y { +class ImageAccessible; + +class ia2AccessibleImage : public IAccessibleImage, public MsaaAccessible { + public: + // IUnknown + DECL_IUNKNOWN_INHERITED + IMPL_IUNKNOWN_REFCOUNTING_INHERITED(MsaaAccessible) + + // IAccessibleAction + // We indirectly inherit IAccessibleAction, which has a get_description + // method, but IAccessibleImage also has a get_description method with a + // different signature. We want both. + using MsaaAccessible::get_description; + + // IAccessibleImage + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_description( + /* [retval][out] */ BSTR* description); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_imagePosition( + /* [in] */ enum IA2CoordinateType coordinateType, + /* [out] */ long* x, + /* [retval][out] */ long* y); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_imageSize( + /* [out] */ long* height, + /* [retval][out] */ long* width); + + protected: + using MsaaAccessible::MsaaAccessible; +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleRelation.cpp b/accessible/windows/ia2/ia2AccessibleRelation.cpp new file mode 100644 index 0000000000..007ca63aa6 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleRelation.cpp @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleRelation.h" + +#include "Relation.h" +#include "nsID.h" + +#include "AccessibleRelation_i.c" + +using namespace mozilla::a11y; + +ia2AccessibleRelation::ia2AccessibleRelation(RelationType aType, Relation* aRel) + : mType(aType) { + Accessible* target = nullptr; + while ((target = aRel->Next())) { + mTargets.AppendElement( + already_AddRefed(MsaaAccessible::NativeAccessible(target))); + } +} + +// IUnknown + +IMPL_IUNKNOWN_QUERY_HEAD(ia2AccessibleRelation) +IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleRelation) +IMPL_IUNKNOWN_QUERY_IFACE(IUnknown) +IMPL_IUNKNOWN_QUERY_TAIL + +// IAccessibleRelation + +STDMETHODIMP +ia2AccessibleRelation::get_relationType(BSTR* aRelationType) { + if (!aRelationType) return E_INVALIDARG; + + *aRelationType = nullptr; + +#define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \ + case RelationType::geckoType: \ + *aRelationType = ::SysAllocString(ia2Type); \ + break; + + switch (mType) { +#include "RelationTypeMap.h" + } + + return *aRelationType ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleRelation::get_localizedRelationType(BSTR* aLocalizedRelationType) { + if (!aLocalizedRelationType) return E_INVALIDARG; + + *aLocalizedRelationType = nullptr; + return E_NOTIMPL; +} + +STDMETHODIMP +ia2AccessibleRelation::get_nTargets(long* aNTargets) { + if (!aNTargets) return E_INVALIDARG; + + *aNTargets = mTargets.Length(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleRelation::get_target(long aTargetIndex, IUnknown** aTarget) { + if (aTargetIndex < 0 || (uint32_t)aTargetIndex >= mTargets.Length() || + !aTarget) + return E_INVALIDARG; + + RefPtr<IUnknown> target = mTargets[aTargetIndex]; + target.forget(aTarget); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleRelation::get_targets(long aMaxTargets, IUnknown** aTargets, + long* aNTargets) { + if (!aNTargets || !aTargets) return E_INVALIDARG; + + *aNTargets = 0; + long maxTargets = mTargets.Length(); + if (maxTargets > aMaxTargets) maxTargets = aMaxTargets; + + for (long idx = 0; idx < maxTargets; idx++) get_target(idx, aTargets + idx); + + *aNTargets = maxTargets; + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleRelation.h b/accessible/windows/ia2/ia2AccessibleRelation.h new file mode 100644 index 0000000000..969abc9eef --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleRelation.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _NS_ACCESSIBLE_RELATION_WRAP_H +#define _NS_ACCESSIBLE_RELATION_WRAP_H + +#include "MsaaAccessible.h" +#include "IUnknownImpl.h" + +#include <utility> +#include "nsTArray.h" + +#include "mozilla/a11y/RelationType.h" +#include "mozilla/a11y/Accessible.h" +#include "AccessibleRelation.h" + +namespace mozilla { +namespace a11y { + +class ia2AccessibleRelation final : public IAccessibleRelation { + public: + ia2AccessibleRelation(RelationType aType, Relation* aRel); + + // IUnknown + DECL_IUNKNOWN + + // IAccessibleRelation + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relationType( + /* [retval][out] */ BSTR* relationType); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedRelationType( + /* [retval][out] */ BSTR* localizedRelationType); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nTargets( + /* [retval][out] */ long* nTargets); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_target( + /* [in] */ long targetIndex, + /* [retval][out] */ IUnknown** target); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_targets( + /* [in] */ long maxTargets, + /* [length_is][size_is][out] */ IUnknown** target, + /* [retval][out] */ long* nTargets); + + inline bool HasTargets() const { return mTargets.Length(); } + + private: + ia2AccessibleRelation(); + ia2AccessibleRelation(const ia2AccessibleRelation&); + ia2AccessibleRelation& operator=(const ia2AccessibleRelation&); + + RelationType mType; + nsTArray<RefPtr<IUnknown>> mTargets; +}; + +/** + * Gecko to IAccessible2 relation types map. + */ + +const WCHAR* const IA2_RELATION_NULL = L""; + +#define RELATIONTYPE(geckoType, name, atkType, msaaType, ia2Type) \ + std::pair<RelationType, const WCHAR* const>(RelationType::geckoType, ia2Type), + +static const std::pair<RelationType, const WCHAR* const> sRelationTypePairs[] = + { +#include "RelationTypeMap.h" +}; + +#undef RELATIONTYPE + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleTable.cpp b/accessible/windows/ia2/ia2AccessibleTable.cpp new file mode 100644 index 0000000000..50bdc79967 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTable.cpp @@ -0,0 +1,534 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleTable.h" + +#include "Accessible2.h" +#include "AccessibleTable_i.c" +#include "AccessibleTable2_i.c" + +#include "IUnknownImpl.h" +#include "mozilla/a11y/Accessible.h" +#include "mozilla/a11y/TableAccessible.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "Statistics.h" + +using namespace mozilla::a11y; + +TableAccessible* ia2AccessibleTable::TableAcc() { + Accessible* acc = Acc(); + return acc ? acc->AsTable() : nullptr; +} + +// IUnknown + +STDMETHODIMP +ia2AccessibleTable::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleTable == iid) { + statistics::IAccessibleTableUsed(); + *ppv = static_cast<IAccessibleTable*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + if (IID_IAccessibleTable2 == iid) { + *ppv = static_cast<IAccessibleTable2*>(this); + (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); + return S_OK; + } + + return ia2AccessibleHypertext::QueryInterface(iid, ppv); +} + +//////////////////////////////////////////////////////////////////////////////// +// IAccessibleTable + +STDMETHODIMP +ia2AccessibleTable::get_accessibleAt(long aRowIdx, long aColIdx, + IUnknown** aAccessible) { + return get_cellAt(aRowIdx, aColIdx, aAccessible); +} + +STDMETHODIMP +ia2AccessibleTable::get_caption(IUnknown** aAccessible) { + if (!aAccessible) return E_INVALIDARG; + + *aAccessible = nullptr; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + Accessible* caption = table->Caption(); + if (!caption) return S_FALSE; + + RefPtr<IAccessible> result = MsaaAccessible::GetFrom(caption); + result.forget(aAccessible); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_childIndex(long aRowIdx, long aColIdx, + long* aChildIdx) { + if (!aChildIdx) return E_INVALIDARG; + + *aChildIdx = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || aColIdx < 0 || + static_cast<uint32_t>(aRowIdx) >= table->RowCount() || + static_cast<uint32_t>(aColIdx) >= table->ColCount()) + return E_INVALIDARG; + + *aChildIdx = table->CellIndexAt(aRowIdx, aColIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_columnDescription(long aColIdx, BSTR* aDescription) { + if (!aDescription) return E_INVALIDARG; + + *aDescription = nullptr; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount()) + return E_INVALIDARG; + + nsAutoString descr; + table->ColDescription(aColIdx, descr); + if (descr.IsEmpty()) return S_FALSE; + + *aDescription = ::SysAllocStringLen(descr.get(), descr.Length()); + return *aDescription ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleTable::get_columnExtentAt(long aRowIdx, long aColIdx, + long* aSpan) { + if (!aSpan) return E_INVALIDARG; + + *aSpan = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || aColIdx < 0 || + static_cast<uint32_t>(aRowIdx) >= table->RowCount() || + static_cast<uint32_t>(aColIdx) >= table->ColCount()) + return E_INVALIDARG; + + *aSpan = table->ColExtentAt(aRowIdx, aColIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_columnHeader(IAccessibleTable** aAccessibleTable, + long* aStartingRowIndex) { + if (!aAccessibleTable || !aStartingRowIndex) return E_INVALIDARG; + + *aAccessibleTable = nullptr; + *aStartingRowIndex = -1; + return E_NOTIMPL; +} + +STDMETHODIMP +ia2AccessibleTable::get_columnIndex(long aCellIdx, long* aColIdx) { + if (!aColIdx) return E_INVALIDARG; + + *aColIdx = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aCellIdx < 0) { + return E_INVALIDARG; + } + + long colIdx = table->ColIndexAt(aCellIdx); + if (colIdx == -1) { // Indicates an error. + return E_INVALIDARG; + } + + *aColIdx = colIdx; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_nColumns(long* aColCount) { + if (!aColCount) return E_INVALIDARG; + + *aColCount = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + *aColCount = table->ColCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_nRows(long* aRowCount) { + if (!aRowCount) return E_INVALIDARG; + + *aRowCount = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + *aRowCount = table->RowCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_nSelectedChildren(long* aChildCount) { + return get_nSelectedCells(aChildCount); +} + +STDMETHODIMP +ia2AccessibleTable::get_nSelectedColumns(long* aColCount) { + if (!aColCount) return E_INVALIDARG; + + *aColCount = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + *aColCount = table->SelectedColCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_nSelectedRows(long* aRowCount) { + if (!aRowCount) return E_INVALIDARG; + + *aRowCount = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + *aRowCount = table->SelectedRowCount(); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_rowDescription(long aRowIdx, BSTR* aDescription) { + if (!aDescription) return E_INVALIDARG; + + *aDescription = nullptr; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount()) + return E_INVALIDARG; + + nsAutoString descr; + table->RowDescription(aRowIdx, descr); + if (descr.IsEmpty()) return S_FALSE; + + *aDescription = ::SysAllocStringLen(descr.get(), descr.Length()); + return *aDescription ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleTable::get_rowExtentAt(long aRowIdx, long aColIdx, long* aSpan) { + if (!aSpan) return E_INVALIDARG; + + *aSpan = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || aColIdx < 0 || + static_cast<uint32_t>(aRowIdx) >= table->RowCount() || + static_cast<uint32_t>(aColIdx) >= table->ColCount()) + return E_INVALIDARG; + + *aSpan = table->RowExtentAt(aRowIdx, aColIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_rowHeader(IAccessibleTable** aAccessibleTable, + long* aStartingColumnIndex) { + if (!aAccessibleTable || !aStartingColumnIndex) return E_INVALIDARG; + + *aAccessibleTable = nullptr; + *aStartingColumnIndex = -1; + return E_NOTIMPL; +} + +STDMETHODIMP +ia2AccessibleTable::get_rowIndex(long aCellIdx, long* aRowIdx) { + if (!aRowIdx) return E_INVALIDARG; + + *aRowIdx = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aCellIdx < 0) { + return E_INVALIDARG; + } + + long rowIdx = table->RowIndexAt(aCellIdx); + if (rowIdx == -1) { // Indicates an error. + return E_INVALIDARG; + } + + *aRowIdx = rowIdx; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_selectedChildren(long aMaxChildren, long** aChildren, + long* aNChildren) { + if (!aChildren || !aNChildren) return E_INVALIDARG; + + *aChildren = nullptr; + *aNChildren = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + AutoTArray<uint32_t, 30> cellIndices; + table->SelectedCellIndices(&cellIndices); + + uint32_t maxCells = cellIndices.Length(); + if (maxCells == 0) return S_FALSE; + + *aChildren = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCells)); + *aNChildren = maxCells; + for (uint32_t i = 0; i < maxCells; i++) (*aChildren)[i] = cellIndices[i]; + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_selectedColumns(long aMaxColumns, long** aColumns, + long* aNColumns) { + return get_selectedColumns(aColumns, aNColumns); +} + +STDMETHODIMP +ia2AccessibleTable::get_selectedRows(long aMaxRows, long** aRows, + long* aNRows) { + return get_selectedRows(aRows, aNRows); +} + +STDMETHODIMP +ia2AccessibleTable::get_summary(IUnknown** aAccessible) { + if (!aAccessible) return E_INVALIDARG; + + // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to + // link an accessible object to specify a summary. There is closes method + // in Table::summary to get a summary as a string which is not mapped + // directly to IAccessible2. + + *aAccessible = nullptr; + return S_FALSE; +} + +STDMETHODIMP +ia2AccessibleTable::get_isColumnSelected(long aColIdx, boolean* aIsSelected) { + if (!aIsSelected) return E_INVALIDARG; + + *aIsSelected = false; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount()) + return E_INVALIDARG; + + *aIsSelected = table->IsColSelected(aColIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_isRowSelected(long aRowIdx, boolean* aIsSelected) { + if (!aIsSelected) return E_INVALIDARG; + + *aIsSelected = false; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount()) + return E_INVALIDARG; + + *aIsSelected = table->IsRowSelected(aRowIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_isSelected(long aRowIdx, long aColIdx, + boolean* aIsSelected) { + if (!aIsSelected) return E_INVALIDARG; + + *aIsSelected = false; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aRowIdx < 0 || aColIdx < 0 || + static_cast<uint32_t>(aColIdx) >= table->ColCount() || + static_cast<uint32_t>(aRowIdx) >= table->RowCount()) + return E_INVALIDARG; + + *aIsSelected = table->IsCellSelected(aRowIdx, aColIdx); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::selectRow(long aRowIdx) { return E_NOTIMPL; } + +STDMETHODIMP +ia2AccessibleTable::selectColumn(long aColIdx) { return E_NOTIMPL; } + +STDMETHODIMP +ia2AccessibleTable::unselectRow(long aRowIdx) { return E_NOTIMPL; } + +STDMETHODIMP +ia2AccessibleTable::unselectColumn(long aColIdx) { return E_NOTIMPL; } + +STDMETHODIMP +ia2AccessibleTable::get_rowColumnExtentsAtIndex(long aCellIdx, long* aRowIdx, + long* aColIdx, + long* aRowExtents, + long* aColExtents, + boolean* aIsSelected) { + if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected) + return E_INVALIDARG; + + *aRowIdx = 0; + *aColIdx = 0; + *aRowExtents = 0; + *aColExtents = 0; + *aIsSelected = false; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + if (aCellIdx < 0) { + return E_INVALIDARG; + } + + int32_t colIdx = 0, rowIdx = 0; + table->RowAndColIndicesAt(aCellIdx, &rowIdx, &colIdx); + if (rowIdx == -1 || colIdx == -1) { // Indicates an error. + return E_INVALIDARG; + } + + *aRowIdx = rowIdx; + *aColIdx = colIdx; + *aRowExtents = table->RowExtentAt(rowIdx, colIdx); + *aColExtents = table->ColExtentAt(rowIdx, colIdx); + *aIsSelected = table->IsCellSelected(rowIdx, colIdx); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_modelChange(IA2TableModelChange* aModelChange) { + return E_NOTIMPL; +} + +//////////////////////////////////////////////////////////////////////////////// +// IAccessibleTable2 + +STDMETHODIMP +ia2AccessibleTable::get_cellAt(long aRowIdx, long aColIdx, IUnknown** aCell) { + if (!aCell) return E_INVALIDARG; + + *aCell = nullptr; + + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + Accessible* cell = table->CellAt(aRowIdx, aColIdx); + if (!cell) return E_INVALIDARG; + + RefPtr<IAccessible> result = MsaaAccessible::GetFrom(cell); + result.forget(aCell); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_nSelectedCells(long* aCellCount) { + if (!aCellCount) return E_INVALIDARG; + + *aCellCount = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + *aCellCount = table->SelectedCellCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_selectedCells(IUnknown*** aCells, + long* aNSelectedCells) { + if (!aCells || !aNSelectedCells) return E_INVALIDARG; + + *aCells = nullptr; + *aNSelectedCells = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + AutoTArray<Accessible*, 30> cells; + table->SelectedCells(&cells); + if (cells.IsEmpty()) return S_FALSE; + + *aCells = static_cast<IUnknown**>( + ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length())); + if (!*aCells) return E_OUTOFMEMORY; + + for (uint32_t i = 0; i < cells.Length(); i++) { + RefPtr<IAccessible> cell = MsaaAccessible::GetFrom(cells[i]); + cell.forget(&(*aCells)[i]); + } + + *aNSelectedCells = cells.Length(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_selectedColumns(long** aColumns, long* aNColumns) { + if (!aColumns || !aNColumns) return E_INVALIDARG; + + *aColumns = nullptr; + *aNColumns = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + AutoTArray<uint32_t, 30> colIndices; + table->SelectedColIndices(&colIndices); + + uint32_t maxCols = colIndices.Length(); + if (maxCols == 0) return S_FALSE; + + *aColumns = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCols)); + *aNColumns = maxCols; + for (uint32_t i = 0; i < maxCols; i++) (*aColumns)[i] = colIndices[i]; + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTable::get_selectedRows(long** aRows, long* aNRows) { + if (!aRows || !aNRows) return E_INVALIDARG; + + *aRows = nullptr; + *aNRows = 0; + TableAccessible* table = TableAcc(); + if (!table) return CO_E_OBJNOTCONNECTED; + + AutoTArray<uint32_t, 30> rowIndices; + table->SelectedRowIndices(&rowIndices); + + uint32_t maxRows = rowIndices.Length(); + if (maxRows == 0) return S_FALSE; + + *aRows = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxRows)); + *aNRows = maxRows; + for (uint32_t i = 0; i < maxRows; i++) (*aRows)[i] = rowIndices[i]; + + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleTable.h b/accessible/windows/ia2/ia2AccessibleTable.h new file mode 100644 index 0000000000..622187c379 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTable.h @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_TABLE_H +#define _ACCESSIBLE_TABLE_H + +#include "AccessibleTable.h" +#include "AccessibleTable2.h" +#include "ia2AccessibleHypertext.h" +#include "IUnknownImpl.h" + +namespace mozilla { +namespace a11y { + +class TableAccessible; + +class ia2AccessibleTable : public IAccessibleTable, + public IAccessibleTable2, + public ia2AccessibleHypertext { + public: + // IUnknown + DECL_IUNKNOWN_INHERITED + IMPL_IUNKNOWN_REFCOUNTING_INHERITED(ia2AccessibleHypertext) + + // IAccessibleTable + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_accessibleAt( + /* [in] */ long row, + /* [in] */ long column, + /* [retval][out] */ IUnknown** accessible); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_caption( + /* [retval][out] */ IUnknown** accessible); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_childIndex( + /* [in] */ long rowIndex, + /* [in] */ long columnIndex, + /* [retval][out] */ long* childIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnDescription( + /* [in] */ long column, + /* [retval][out] */ BSTR* description); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnExtentAt( + /* [in] */ long row, + /* [in] */ long column, + /* [retval][out] */ long* nColumnsSpanned); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnHeader( + /* [out] */ IAccessibleTable** accessibleTable, + /* [retval][out] */ long* startingRowIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnIndex( + /* [in] */ long childIndex, + /* [retval][out] */ long* columnIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nColumns( + /* [retval][out] */ long* columnCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nRows( + /* [retval][out] */ long* rowCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedChildren( + /* [retval][out] */ long* childCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedColumns( + /* [retval][out] */ long* columnCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedRows( + /* [retval][out] */ long* rowCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowDescription( + /* [in] */ long row, + /* [retval][out] */ BSTR* description); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowExtentAt( + /* [in] */ long row, + /* [in] */ long column, + /* [retval][out] */ long* nRowsSpanned); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowHeader( + /* [out] */ IAccessibleTable** accessibleTable, + /* [retval][out] */ long* startingColumnIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowIndex( + /* [in] */ long childIndex, + /* [retval][out] */ long* rowIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedChildren( + /* [in] */ long maxChildren, + /* [length_is][length_is][size_is][size_is][out] */ long** children, + /* [retval][out] */ long* nChildren); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedColumns( + /* [in] */ long maxColumns, + /* [length_is][length_is][size_is][size_is][out] */ long** columns, + /* [retval][out] */ long* nColumns); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedRows( + /* [in] */ long maxRows, + /* [length_is][length_is][size_is][size_is][out] */ long** rows, + /* [retval][out] */ long* nRows); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_summary( + /* [retval][out] */ IUnknown** accessible); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isColumnSelected( + /* [in] */ long column, + /* [retval][out] */ boolean* isSelected); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isRowSelected( + /* [in] */ long row, + /* [retval][out] */ boolean* isSelected); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isSelected( + /* [in] */ long row, + /* [in] */ long column, + /* [retval][out] */ boolean* isSelected); + + virtual HRESULT STDMETHODCALLTYPE selectRow( + /* [in] */ long row); + + virtual HRESULT STDMETHODCALLTYPE selectColumn( + /* [in] */ long column); + + virtual HRESULT STDMETHODCALLTYPE unselectRow( + /* [in] */ long row); + + virtual HRESULT STDMETHODCALLTYPE unselectColumn( + /* [in] */ long column); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowColumnExtentsAtIndex( + /* [in] */ long index, + /* [out] */ long* row, + /* [out] */ long* column, + /* [out] */ long* rowExtents, + /* [out] */ long* columnExtents, + /* [retval][out] */ boolean* isSelected); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_modelChange( + /* [retval][out] */ IA2TableModelChange* modelChange); + + // IAccessibleTable2 + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_cellAt( + /* [in] */ long row, + /* [in] */ long column, + /* [out, retval] */ IUnknown** cell); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelectedCells( + /* [out, retval] */ long* cellCount); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedCells( + /* [out, size_is(,*nSelectedCells,)] */ IUnknown*** cells, + /* [out, retval] */ long* nSelectedCells); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedColumns( + /* [out, size_is(,*nColumns)] */ long** selectedColumns, + /* [out, retval] */ long* nColumns); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedRows( + /* [out, size_is(,*nRows)] */ long** selectedRows, + /* [out, retval] */ long* nRows); + + protected: + using ia2AccessibleHypertext::ia2AccessibleHypertext; + + private: + TableAccessible* TableAcc(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleTableCell.cpp b/accessible/windows/ia2/ia2AccessibleTableCell.cpp new file mode 100644 index 0000000000..0204983a08 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTableCell.cpp @@ -0,0 +1,186 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleTableCell.h" + +#include "AccessibleTable2_i.c" +#include "AccessibleTableCell_i.c" + +#include "IUnknownImpl.h" +#include "mozilla/a11y/Accessible.h" +#include "mozilla/a11y/TableAccessible.h" +#include "mozilla/a11y/TableCellAccessible.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +using namespace mozilla::a11y; + +TableCellAccessible* ia2AccessibleTableCell::CellAcc() { + Accessible* acc = Acc(); + return acc ? acc->AsTableCell() : nullptr; +} + +// IUnknown +IMPL_IUNKNOWN_QUERY_HEAD(ia2AccessibleTableCell) +IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleTableCell) +IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(ia2AccessibleHypertext) + +//////////////////////////////////////////////////////////////////////////////// +// IAccessibleTableCell + +STDMETHODIMP +ia2AccessibleTableCell::get_table(IUnknown** aTable) { + if (!aTable) return E_INVALIDARG; + + *aTable = nullptr; + TableCellAccessible* tableCell = CellAcc(); + if (!tableCell) return CO_E_OBJNOTCONNECTED; + + TableAccessible* table = tableCell->Table(); + if (!table) return E_FAIL; + + Accessible* tableAcc = table->AsAccessible(); + RefPtr<IAccessible> result = MsaaAccessible::GetFrom(tableAcc); + result.forget(aTable); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_columnExtent(long* aSpan) { + if (!aSpan) return E_INVALIDARG; + + *aSpan = 0; + TableCellAccessible* tableCell = CellAcc(); + if (!tableCell) return CO_E_OBJNOTCONNECTED; + + *aSpan = tableCell->ColExtent(); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_columnHeaderCells(IUnknown*** aCellAccessibles, + long* aNColumnHeaderCells) { + if (!aCellAccessibles || !aNColumnHeaderCells) return E_INVALIDARG; + + *aCellAccessibles = nullptr; + *aNColumnHeaderCells = 0; + TableCellAccessible* tableCell = CellAcc(); + if (!tableCell) return CO_E_OBJNOTCONNECTED; + + AutoTArray<Accessible*, 10> cells; + tableCell->ColHeaderCells(&cells); + + *aNColumnHeaderCells = cells.Length(); + *aCellAccessibles = static_cast<IUnknown**>( + ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length())); + + if (!*aCellAccessibles) return E_OUTOFMEMORY; + + for (uint32_t i = 0; i < cells.Length(); i++) { + RefPtr<IAccessible> iaCell = MsaaAccessible::GetFrom(cells[i]); + iaCell.forget(&(*aCellAccessibles)[i]); + } + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_columnIndex(long* aColIdx) { + if (!aColIdx) return E_INVALIDARG; + + *aColIdx = -1; + TableCellAccessible* tableCell = CellAcc(); + if (!tableCell) return CO_E_OBJNOTCONNECTED; + + *aColIdx = tableCell->ColIdx(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_rowExtent(long* aSpan) { + if (!aSpan) return E_INVALIDARG; + + *aSpan = 0; + TableCellAccessible* tableCell = CellAcc(); + if (!tableCell) return CO_E_OBJNOTCONNECTED; + + *aSpan = tableCell->RowExtent(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_rowHeaderCells(IUnknown*** aCellAccessibles, + long* aNRowHeaderCells) { + if (!aCellAccessibles || !aNRowHeaderCells) return E_INVALIDARG; + + *aCellAccessibles = nullptr; + *aNRowHeaderCells = 0; + TableCellAccessible* tableCell = CellAcc(); + if (!tableCell) return CO_E_OBJNOTCONNECTED; + + AutoTArray<Accessible*, 10> cells; + tableCell->RowHeaderCells(&cells); + + *aNRowHeaderCells = cells.Length(); + *aCellAccessibles = static_cast<IUnknown**>( + ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length())); + if (!*aCellAccessibles) return E_OUTOFMEMORY; + + for (uint32_t i = 0; i < cells.Length(); i++) { + RefPtr<IAccessible> iaCell = MsaaAccessible::GetFrom(cells[i]); + iaCell.forget(&(*aCellAccessibles)[i]); + } + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_rowIndex(long* aRowIdx) { + if (!aRowIdx) return E_INVALIDARG; + + *aRowIdx = -1; + TableCellAccessible* tableCell = CellAcc(); + if (!tableCell) return CO_E_OBJNOTCONNECTED; + + *aRowIdx = tableCell->RowIdx(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_rowColumnExtents(long* aRowIdx, long* aColIdx, + long* aRowExtents, + long* aColExtents, + boolean* aIsSelected) { + if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected) + return E_INVALIDARG; + + *aRowIdx = *aColIdx = *aRowExtents = *aColExtents = 0; + *aIsSelected = false; + TableCellAccessible* tableCell = CellAcc(); + if (!tableCell) return CO_E_OBJNOTCONNECTED; + + *aRowIdx = tableCell->RowIdx(); + *aColIdx = tableCell->ColIdx(); + *aRowExtents = tableCell->RowExtent(); + *aColExtents = tableCell->ColExtent(); + *aIsSelected = tableCell->Selected(); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTableCell::get_isSelected(boolean* aIsSelected) { + if (!aIsSelected) return E_INVALIDARG; + + *aIsSelected = false; + TableCellAccessible* tableCell = CellAcc(); + if (!tableCell) return CO_E_OBJNOTCONNECTED; + + *aIsSelected = tableCell->Selected(); + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleTableCell.h b/accessible/windows/ia2/ia2AccessibleTableCell.h new file mode 100644 index 0000000000..04e978cb96 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTableCell.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_TABLECELL_H +#define _ACCESSIBLE_TABLECELL_H + +#include "AccessibleTableCell.h" +#include "ia2AccessibleHypertext.h" +#include "IUnknownImpl.h" + +namespace mozilla { +namespace a11y { +class TableCellAccessible; + +class ia2AccessibleTableCell : public IAccessibleTableCell, + public ia2AccessibleHypertext { + public: + // IUnknown + DECL_IUNKNOWN_INHERITED + IMPL_IUNKNOWN_REFCOUNTING_INHERITED(ia2AccessibleHypertext) + + // IAccessibleTableCell + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_table( + /* [out, retval] */ IUnknown** table); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnExtent( + /* [out, retval] */ long* nColumnsSpanned); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnHeaderCells( + /* [out, size_is(,*nColumnHeaderCells,)] */ IUnknown*** cellAccessibles, + /* [out, retval] */ long* nColumnHeaderCells); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_columnIndex( + /* [out, retval] */ long* columnIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowExtent( + /* [out, retval] */ long* nRowsSpanned); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowHeaderCells( + /* [out, size_is(,*nRowHeaderCells,)] */ IUnknown*** cellAccessibles, + /* [out, retval] */ long* nRowHeaderCells); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowIndex( + /* [out, retval] */ long* rowIndex); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_rowColumnExtents( + /* [out] */ long* row, + /* [out] */ long* column, + /* [out] */ long* rowExtents, + /* [out] */ long* columnExtents, + /* [out, retval] */ boolean* isSelected); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isSelected( + /* [out, retval] */ boolean* isSelected); + + protected: + using ia2AccessibleHypertext::ia2AccessibleHypertext; + + private: + TableCellAccessible* CellAcc(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleText.cpp b/accessible/windows/ia2/ia2AccessibleText.cpp new file mode 100644 index 0000000000..29589fb2df --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleText.cpp @@ -0,0 +1,466 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2Accessible.h" +#include "ia2AccessibleHypertext.h" +#include "ia2AccessibleText.h" + +#include "AccessibleText_i.c" + +#include "mozilla/a11y/HyperTextAccessibleBase.h" +#include "mozilla/ClearOnShutdown.h" + +using namespace mozilla::a11y; + +HyperTextAccessibleBase* ia2AccessibleText::sLastTextChangeAcc = nullptr; +mozilla::StaticAutoPtr<nsString> ia2AccessibleText::sLastTextChangeString; +uint32_t ia2AccessibleText::sLastTextChangeStart = 0; +uint32_t ia2AccessibleText::sLastTextChangeEnd = 0; +bool ia2AccessibleText::sLastTextChangeWasInsert = false; + +HyperTextAccessibleBase* ia2AccessibleText::TextAcc() { + auto hyp = static_cast<ia2AccessibleHypertext*>(this); + Accessible* acc = hyp->Acc(); + return acc ? acc->AsHyperTextBase() : nullptr; +} + +// IAccessibleText + +STDMETHODIMP +ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + return textAcc->AddToSelection(aStartOffset, aEndOffset) ? S_OK + : E_INVALIDARG; +} + +STDMETHODIMP +ia2AccessibleText::get_attributes(long aOffset, long* aStartOffset, + long* aEndOffset, BSTR* aTextAttributes) { + if (!aStartOffset || !aEndOffset || !aTextAttributes) return E_INVALIDARG; + + *aStartOffset = 0; + *aEndOffset = 0; + *aTextAttributes = nullptr; + + int32_t startOffset = 0, endOffset = 0; + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + RefPtr<AccAttributes> attributes = + textAcc->TextAttributes(true, aOffset, &startOffset, &endOffset); + + HRESULT hr = + ia2Accessible::ConvertToIA2Attributes(attributes, aTextAttributes); + if (FAILED(hr)) return hr; + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::get_caretOffset(long* aOffset) { + if (!aOffset) return E_INVALIDARG; + + *aOffset = -1; + + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + *aOffset = textAcc->CaretOffset(); + + return *aOffset != -1 ? S_OK : S_FALSE; +} + +STDMETHODIMP +ia2AccessibleText::get_characterExtents(long aOffset, + enum IA2CoordinateType aCoordType, + long* aX, long* aY, long* aWidth, + long* aHeight) { + if (!aX || !aY || !aWidth || !aHeight) return E_INVALIDARG; + *aX = *aY = *aWidth = *aHeight = 0; + + uint32_t geckoCoordType = + (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) + ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE + : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + LayoutDeviceIntRect rect; + auto textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + rect = textAcc->CharBounds(aOffset, geckoCoordType); + + // Can't use GetRect() because of long vs. int32_t mismatch + *aX = rect.X(); + *aY = rect.Y(); + *aWidth = rect.Width(); + *aHeight = rect.Height(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::get_nSelections(long* aNSelections) { + if (!aNSelections) return E_INVALIDARG; + *aNSelections = 0; + + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + *aNSelections = textAcc->SelectionCount(); + + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::get_offsetAtPoint(long aX, long aY, + enum IA2CoordinateType aCoordType, + long* aOffset) { + if (!aOffset) return E_INVALIDARG; + *aOffset = 0; + + uint32_t geckoCoordType = + (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) + ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE + : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + *aOffset = textAcc->OffsetAtPoint(aX, aY, geckoCoordType); + + return *aOffset == -1 ? S_FALSE : S_OK; +} + +STDMETHODIMP +ia2AccessibleText::get_selection(long aSelectionIndex, long* aStartOffset, + long* aEndOffset) { + if (!aStartOffset || !aEndOffset) return E_INVALIDARG; + *aStartOffset = *aEndOffset = 0; + + int32_t startOffset = 0, endOffset = 0; + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->SelectionBoundsAt(aSelectionIndex, &startOffset, &endOffset)) { + return E_INVALIDARG; + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR* aText) { + if (!aText) return E_INVALIDARG; + + *aText = nullptr; + + nsAutoString text; + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) { + return E_INVALIDARG; + } + + textAcc->TextSubstring(aStartOffset, aEndOffset, text); + + if (text.IsEmpty()) return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleText::get_textBeforeOffset(long aOffset, + enum IA2TextBoundaryType aBoundaryType, + long* aStartOffset, long* aEndOffset, + BSTR* aText) { + if (!aStartOffset || !aEndOffset || !aText) return E_INVALIDARG; + + *aStartOffset = *aEndOffset = 0; + *aText = nullptr; + + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + nsAutoString text; + int32_t startOffset = 0, endOffset = 0; + + if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { + startOffset = 0; + endOffset = textAcc->CharacterCount(); + textAcc->TextSubstring(startOffset, endOffset, text); + } else { + AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); + if (boundaryType == -1) return S_FALSE; + + textAcc->TextBeforeOffset(aOffset, boundaryType, &startOffset, &endOffset, + text); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + if (text.IsEmpty()) return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleText::get_textAfterOffset(long aOffset, + enum IA2TextBoundaryType aBoundaryType, + long* aStartOffset, long* aEndOffset, + BSTR* aText) { + if (!aStartOffset || !aEndOffset || !aText) return E_INVALIDARG; + + *aStartOffset = 0; + *aEndOffset = 0; + *aText = nullptr; + + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + nsAutoString text; + int32_t startOffset = 0, endOffset = 0; + + if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { + startOffset = 0; + endOffset = textAcc->CharacterCount(); + textAcc->TextSubstring(startOffset, endOffset, text); + } else { + AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); + if (boundaryType == -1) return S_FALSE; + textAcc->TextAfterOffset(aOffset, boundaryType, &startOffset, &endOffset, + text); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + if (text.IsEmpty()) return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleText::get_textAtOffset(long aOffset, + enum IA2TextBoundaryType aBoundaryType, + long* aStartOffset, long* aEndOffset, + BSTR* aText) { + if (!aStartOffset || !aEndOffset || !aText) return E_INVALIDARG; + + *aStartOffset = *aEndOffset = 0; + *aText = nullptr; + + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + nsAutoString text; + int32_t startOffset = 0, endOffset = 0; + if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { + startOffset = 0; + endOffset = textAcc->CharacterCount(); + textAcc->TextSubstring(startOffset, endOffset, text); + } else { + AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); + if (boundaryType == -1) return S_FALSE; + textAcc->TextAtOffset(aOffset, boundaryType, &startOffset, &endOffset, + text); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + if (text.IsEmpty()) return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; +} + +STDMETHODIMP +ia2AccessibleText::removeSelection(long aSelectionIndex) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + return textAcc->RemoveFromSelection(aSelectionIndex) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP +ia2AccessibleText::setCaretOffset(long aOffset) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG; + + textAcc->SetCaretOffset(aOffset); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::setSelection(long aSelectionIndex, long aStartOffset, + long aEndOffset) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + return textAcc->SetSelectionBoundsAt(aSelectionIndex, aStartOffset, + aEndOffset) + ? S_OK + : E_INVALIDARG; +} + +STDMETHODIMP +ia2AccessibleText::get_nCharacters(long* aNCharacters) { + if (!aNCharacters) return E_INVALIDARG; + *aNCharacters = 0; + + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) return CO_E_OBJNOTCONNECTED; + + *aNCharacters = textAcc->CharacterCount(); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex, + enum IA2ScrollType aScrollType) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) return E_INVALIDARG; + + textAcc->ScrollSubstringTo(aStartIndex, aEndIndex, aScrollType); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::scrollSubstringToPoint(long aStartIndex, long aEndIndex, + enum IA2CoordinateType aCoordType, + long aX, long aY) { + HyperTextAccessibleBase* textAcc = TextAcc(); + if (!textAcc) { + return CO_E_OBJNOTCONNECTED; + } + if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) { + return E_INVALIDARG; + } + uint32_t geckoCoordType = + (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) + ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE + : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex, geckoCoordType, aX, + aY); + return S_OK; +} + +STDMETHODIMP +ia2AccessibleText::get_newText(IA2TextSegment* aNewText) { + return GetModifiedText(true, aNewText); +} + +STDMETHODIMP +ia2AccessibleText::get_oldText(IA2TextSegment* aOldText) { + return GetModifiedText(false, aOldText); +} + +// ia2AccessibleText + +HRESULT +ia2AccessibleText::GetModifiedText(bool aGetInsertedText, + IA2TextSegment* aText) { + if (!aText) return E_INVALIDARG; + + if (!sLastTextChangeAcc) return S_OK; + + if (aGetInsertedText != sLastTextChangeWasInsert) return S_OK; + + if (sLastTextChangeAcc != TextAcc()) return S_OK; + + aText->start = sLastTextChangeStart; + aText->end = sLastTextChangeEnd; + + if (sLastTextChangeString->IsEmpty()) return S_FALSE; + + aText->text = ::SysAllocStringLen(sLastTextChangeString->get(), + sLastTextChangeString->Length()); + return aText->text ? S_OK : E_OUTOFMEMORY; +} + +AccessibleTextBoundary ia2AccessibleText::GetGeckoTextBoundary( + enum IA2TextBoundaryType aBoundaryType) { + switch (aBoundaryType) { + case IA2_TEXT_BOUNDARY_CHAR: + return nsIAccessibleText::BOUNDARY_CHAR; + case IA2_TEXT_BOUNDARY_WORD: + return nsIAccessibleText::BOUNDARY_WORD_START; + case IA2_TEXT_BOUNDARY_LINE: + return nsIAccessibleText::BOUNDARY_LINE_START; + case IA2_TEXT_BOUNDARY_PARAGRAPH: + return nsIAccessibleText::BOUNDARY_PARAGRAPH; + // case IA2_TEXT_BOUNDARY_SENTENCE: + // XXX: not implemented + default: + return -1; + } +} + +void ia2AccessibleText::InitTextChangeData() { + ClearOnShutdown(&sLastTextChangeString); +} + +void ia2AccessibleText::UpdateTextChangeData(HyperTextAccessibleBase* aAcc, + bool aInsert, + const nsAString& aStr, + int32_t aStart, uint32_t aLen) { + if (!sLastTextChangeString) sLastTextChangeString = new nsString(); + + sLastTextChangeAcc = aAcc; + sLastTextChangeStart = aStart; + sLastTextChangeEnd = aStart + aLen; + sLastTextChangeWasInsert = aInsert; + *sLastTextChangeString = aStr; +} diff --git a/accessible/windows/ia2/ia2AccessibleText.h b/accessible/windows/ia2/ia2AccessibleText.h new file mode 100644 index 0000000000..92c255d44a --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleText.h @@ -0,0 +1,246 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _ACCESSIBLE_TEXT_H +#define _ACCESSIBLE_TEXT_H + +#include <utility> +#include "AccessibleText.h" +#include "nsIAccessibleText.h" + +namespace mozilla { +template <class T> +class StaticAutoPtr; +template <class T> +class StaticRefPtr; + +namespace a11y { +class HyperTextAccessibleBase; + +class ia2AccessibleText : public IAccessibleText { + public: + // IAccessibleText + virtual HRESULT STDMETHODCALLTYPE addSelection( + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_attributes( + /* [in] */ long offset, + /* [out] */ long* startOffset, + /* [out] */ long* endOffset, + /* [retval][out] */ BSTR* textAttributes); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_caretOffset( + /* [retval][out] */ long* offset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_characterExtents( + /* [in] */ long offset, + /* [in] */ enum IA2CoordinateType coordType, + /* [out] */ long* x, + /* [out] */ long* y, + /* [out] */ long* width, + /* [retval][out] */ long* height); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nSelections( + /* [retval][out] */ long* nSelections); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_offsetAtPoint( + /* [in] */ long x, + /* [in] */ long y, + /* [in] */ enum IA2CoordinateType coordType, + /* [retval][out] */ long* offset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selection( + /* [in] */ long selectionIndex, + /* [out] */ long* startOffset, + /* [retval][out] */ long* endOffset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_text( + /* [in] */ long startOffset, + /* [in] */ long endOffset, + /* [retval][out] */ BSTR* text); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_textBeforeOffset( + /* [in] */ long offset, + /* [in] */ enum IA2TextBoundaryType boundaryType, + /* [out] */ long* startOffset, + /* [out] */ long* endOffset, + /* [retval][out] */ BSTR* text); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_textAfterOffset( + /* [in] */ long offset, + /* [in] */ enum IA2TextBoundaryType boundaryType, + /* [out] */ long* startOffset, + /* [out] */ long* endOffset, + /* [retval][out] */ BSTR* text); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_textAtOffset( + /* [in] */ long offset, + /* [in] */ enum IA2TextBoundaryType boundaryType, + /* [out] */ long* startOffset, + /* [out] */ long* endOffset, + /* [retval][out] */ BSTR* text); + + virtual HRESULT STDMETHODCALLTYPE removeSelection( + /* [in] */ long selectionIndex); + + virtual HRESULT STDMETHODCALLTYPE setCaretOffset( + /* [in] */ long offset); + + virtual HRESULT STDMETHODCALLTYPE setSelection( + /* [in] */ long selectionIndex, + /* [in] */ long startOffset, + /* [in] */ long endOffset); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nCharacters( + /* [retval][out] */ long* nCharacters); + + virtual HRESULT STDMETHODCALLTYPE scrollSubstringTo( + /* [in] */ long startIndex, + /* [in] */ long endIndex, + /* [in] */ enum IA2ScrollType scrollType); + + virtual HRESULT STDMETHODCALLTYPE scrollSubstringToPoint( + /* [in] */ long startIndex, + /* [in] */ long endIndex, + /* [in] */ enum IA2CoordinateType coordinateType, + /* [in] */ long x, + /* [in] */ long y); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_newText( + /* [retval][out] */ IA2TextSegment* newText); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_oldText( + /* [retval][out] */ IA2TextSegment* oldText); + + static void InitTextChangeData(); + static void UpdateTextChangeData(HyperTextAccessibleBase* aAcc, bool aInsert, + const nsAString& aStr, int32_t aStart, + uint32_t aLen); + + protected: + // This can't be a RefPtr because RemoteAccessibles aren't ref counted. It + // can't be an id because this is global and ids are only unique within the + // document. Since this is only used for comparison, we use a raw pointer. + // This should *never* be dereferenced, only used for comparison! + static HyperTextAccessibleBase* sLastTextChangeAcc; + static StaticAutoPtr<nsString> sLastTextChangeString; + static bool sLastTextChangeWasInsert; + static uint32_t sLastTextChangeStart; + static uint32_t sLastTextChangeEnd; + + private: + HRESULT GetModifiedText(bool aGetInsertedText, IA2TextSegment* aNewText); + AccessibleTextBoundary GetGeckoTextBoundary( + enum IA2TextBoundaryType coordinateType); + HyperTextAccessibleBase* TextAcc(); +}; + +} // 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/ia2AccessibleTextSelectionContainer.cpp b/accessible/windows/ia2/ia2AccessibleTextSelectionContainer.cpp new file mode 100644 index 0000000000..0360cc2028 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTextSelectionContainer.cpp @@ -0,0 +1,126 @@ +/* -*- 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 "ia2AccessibleTextSelectionContainer.h" + +#include "AccessibleTextSelectionContainer_i.c" +#include "ia2AccessibleHypertext.h" +#include "mozilla/a11y/HyperTextAccessibleBase.h" +#include "TextRange.h" +#include "TextLeafRange.h" + +using namespace mozilla::a11y; + +// IAccessibleTextSelectionContainer + +STDMETHODIMP +ia2AccessibleTextSelectionContainer::get_selections( + IA2TextSelection** selections, long* nSelections) { + if (!selections || !nSelections) { + return E_INVALIDARG; + } + *nSelections = 0; + HyperTextAccessibleBase* text = TextAcc(); + if (!text) { + return CO_E_OBJNOTCONNECTED; + } + AutoTArray<TextRange, 1> ranges; + text->CroppedSelectionRanges(ranges); + *nSelections = ranges.Length(); + *selections = static_cast<IA2TextSelection*>( + ::CoTaskMemAlloc(sizeof(IA2TextSelection) * *nSelections)); + if (!*selections) { + return E_OUTOFMEMORY; + } + for (uint32_t idx = 0; idx < static_cast<uint32_t>(*nSelections); idx++) { + RefPtr<IAccessibleText> startObj = + GetIATextFrom(ranges[idx].StartContainer()); + startObj.forget(&(*selections)[idx].startObj); + (*selections)[idx].startOffset = ranges[idx].StartOffset(); + RefPtr<IAccessibleText> endObj = GetIATextFrom(ranges[idx].EndContainer()); + endObj.forget(&(*selections)[idx].endObj); + (*selections)[idx].endOffset = ranges[idx].EndOffset(); + // XXX Expose this properly somehow. + (*selections)[idx].startIsActive = true; + } + return S_OK; +} + +STDMETHODIMP +ia2AccessibleTextSelectionContainer::setSelections( + long nSelections, IA2TextSelection* selections) { + if (nSelections < 0 || (nSelections > 0 && !selections)) { + return E_INVALIDARG; + } + HyperTextAccessibleBase* text = TextAcc(); + if (!text) { + return CO_E_OBJNOTCONNECTED; + } + // Build and validate new selection ranges. + AutoTArray<TextLeafRange, 1> newRanges; + newRanges.SetCapacity(nSelections); + for (long r = 0; r < nSelections; ++r) { + TextLeafRange range(GetTextLeafPointFrom(selections[r].startObj, + selections[r].startOffset, false), + GetTextLeafPointFrom(selections[r].endObj, + selections[r].endOffset, true)); + if (!range) { + return E_INVALIDARG; + } + newRanges.AppendElement(range); + } + // Get the number of existing selections. We use SelectionRanges rather than + // SelectionCount because SelectionCount is restricted to this Accessible, + // whereas we want all selections within the control/document. + AutoTArray<TextRange, 1> oldRanges; + text->SelectionRanges(&oldRanges); + // Set the new selections. + for (long r = 0; r < nSelections; ++r) { + newRanges[r].SetSelection(r); + } + // Remove any remaining old selections if there were more than nSelections. + for (long r = nSelections; r < static_cast<long>(oldRanges.Length()); ++r) { + text->RemoveFromSelection(r); + } + return S_OK; +} + +// ia2AccessibleTextSelectionContainer + +HyperTextAccessibleBase* ia2AccessibleTextSelectionContainer::TextAcc() { + auto hyp = static_cast<ia2AccessibleHypertext*>(this); + Accessible* acc = hyp->Acc(); + return acc ? acc->AsHyperTextBase() : nullptr; +} + +/* static */ +RefPtr<IAccessibleText> ia2AccessibleTextSelectionContainer::GetIATextFrom( + Accessible* aAcc) { + MsaaAccessible* msaa = MsaaAccessible::GetFrom(aAcc); + MOZ_ASSERT(msaa); + RefPtr<IAccessibleText> text; + msaa->QueryInterface(IID_IAccessibleText, getter_AddRefs(text)); + MOZ_ASSERT(text); + return text; +} + +/* static */ +TextLeafPoint ia2AccessibleTextSelectionContainer::GetTextLeafPointFrom( + IAccessibleText* aText, long aOffset, bool aDescendToEnd) { + if (!aText) { + return TextLeafPoint(); + } + Accessible* acc = MsaaAccessible::GetAccessibleFrom(aText); + if (!acc) { + return TextLeafPoint(); + } + HyperTextAccessibleBase* hyp = acc->AsHyperTextBase(); + if (!hyp) { + return TextLeafPoint(); + } + return hyp->ToTextLeafPoint(aOffset, aDescendToEnd); +} diff --git a/accessible/windows/ia2/ia2AccessibleTextSelectionContainer.h b/accessible/windows/ia2/ia2AccessibleTextSelectionContainer.h new file mode 100644 index 0000000000..77ab40c1ed --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleTextSelectionContainer.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_WINDOWS_IA2_ACCESSIBLETEXTSELECTIONCONTAINER_H_ +#define ACCESSIBLE_WINDOWS_IA2_ACCESSIBLETEXTSELECTIONCONTAINER_H_ + +#include "AccessibleTextSelectionContainer.h" +#include "mozilla/Attributes.h" + +template <class T> +class RefPtr; + +namespace mozilla::a11y { +class Accessible; +class HyperTextAccessibleBase; +class TextLeafPoint; + +class ia2AccessibleTextSelectionContainer + : public IAccessibleTextSelectionContainer { + public: + // IAccessibleTextSelectionContainer + /* [propget] */ HRESULT STDMETHODCALLTYPE get_selections( + /* [out, size_is(,*nSelections)] */ IA2TextSelection** selections, + /* [out, retval] */ long* nSelections) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + HRESULT STDMETHODCALLTYPE setSelections( + /* [in] */ long nSelections, + /* [in, size_is(nSelections)] */ IA2TextSelection* selections) override; + + private: + HyperTextAccessibleBase* TextAcc(); + static RefPtr<IAccessibleText> GetIATextFrom(Accessible* aAcc); + static TextLeafPoint GetTextLeafPointFrom(IAccessibleText* aText, + long aOffset, bool aDescendToEnd); +}; + +} // namespace mozilla::a11y + +#endif diff --git a/accessible/windows/ia2/ia2AccessibleValue.cpp b/accessible/windows/ia2/ia2AccessibleValue.cpp new file mode 100644 index 0000000000..b0b9a729e3 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleValue.cpp @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ia2AccessibleValue.h" + +#include "AccessibleValue_i.c" + +#include "AccessibleWrap.h" +#include "LocalAccessible-inl.h" +#include "IUnknownImpl.h" + +#include "mozilla/FloatingPoint.h" + +using namespace mozilla::a11y; + +AccessibleWrap* ia2AccessibleValue::LocalAcc() { + return static_cast<MsaaAccessible*>(this)->LocalAcc(); +} + +Accessible* ia2AccessibleValue::Acc() { + return static_cast<MsaaAccessible*>(this)->Acc(); +} + +// IUnknown + +STDMETHODIMP +ia2AccessibleValue::QueryInterface(REFIID iid, void** ppv) { + if (!ppv) return E_INVALIDARG; + + *ppv = nullptr; + + if (IID_IAccessibleValue == iid) { + Accessible* valueAcc = Acc(); + if (valueAcc && valueAcc->HasNumericValue()) { + RefPtr<IAccessibleValue> result = this; + result.forget(ppv); + return S_OK; + } + + return E_NOINTERFACE; + } + + return E_NOINTERFACE; +} + +// IAccessibleValue + +STDMETHODIMP +ia2AccessibleValue::get_currentValue(VARIANT* aCurrentValue) { + if (!aCurrentValue) return E_INVALIDARG; + + VariantInit(aCurrentValue); + + Accessible* valueAcc = Acc(); + if (!valueAcc) { + return CO_E_OBJNOTCONNECTED; + } + double currentValue; + + currentValue = valueAcc->CurValue(); + + if (std::isnan(currentValue)) return S_FALSE; + + aCurrentValue->vt = VT_R8; + aCurrentValue->dblVal = currentValue; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleValue::setCurrentValue(VARIANT aValue) { + if (aValue.vt != VT_R8) return E_INVALIDARG; + + Accessible* valueAcc = Acc(); + if (!valueAcc) { + return CO_E_OBJNOTCONNECTED; + } + + return valueAcc->SetCurValue(aValue.dblVal) ? S_OK : E_FAIL; +} + +STDMETHODIMP +ia2AccessibleValue::get_maximumValue(VARIANT* aMaximumValue) { + if (!aMaximumValue) return E_INVALIDARG; + + VariantInit(aMaximumValue); + + Accessible* valueAcc = Acc(); + if (!valueAcc) { + return CO_E_OBJNOTCONNECTED; + } + double maximumValue; + + maximumValue = valueAcc->MaxValue(); + + if (std::isnan(maximumValue)) return S_FALSE; + + aMaximumValue->vt = VT_R8; + aMaximumValue->dblVal = maximumValue; + return S_OK; +} + +STDMETHODIMP +ia2AccessibleValue::get_minimumValue(VARIANT* aMinimumValue) { + if (!aMinimumValue) return E_INVALIDARG; + + VariantInit(aMinimumValue); + + Accessible* valueAcc = Acc(); + if (!valueAcc) { + return CO_E_OBJNOTCONNECTED; + } + double minimumValue; + + minimumValue = valueAcc->MinValue(); + + if (std::isnan(minimumValue)) return S_FALSE; + + aMinimumValue->vt = VT_R8; + aMinimumValue->dblVal = minimumValue; + return S_OK; +} diff --git a/accessible/windows/ia2/ia2AccessibleValue.h b/accessible/windows/ia2/ia2AccessibleValue.h new file mode 100644 index 0000000000..9238b827b5 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleValue.h @@ -0,0 +1,44 @@ +/* -*- 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 "mozilla/a11y/Accessible.h" +#include "AccessibleValue.h" + +namespace mozilla { +namespace a11y { +class AccessibleWrap; + +class ia2AccessibleValue : public IAccessibleValue { + public: + // IUnknown + STDMETHODIMP QueryInterface(REFIID, void**); + + // IAccessibleValue + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_currentValue( + /* [retval][out] */ VARIANT* currentValue); + + virtual HRESULT STDMETHODCALLTYPE setCurrentValue( + /* [in] */ VARIANT value); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_maximumValue( + /* [retval][out] */ VARIANT* maximumValue); + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_minimumValue( + /* [retval][out] */ VARIANT* minimumValue); + + private: + Accessible* Acc(); + AccessibleWrap* LocalAcc(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/windows/ia2/moz.build b/accessible/windows/ia2/moz.build new file mode 100644 index 0000000000..53f930fd5a --- /dev/null +++ b/accessible/windows/ia2/moz.build @@ -0,0 +1,61 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS += [ + "ia2Accessible.h", + "ia2AccessibleAction.h", + "ia2AccessibleComponent.h", + "ia2AccessibleEditableText.h", + "ia2AccessibleHyperlink.h", + "ia2AccessibleHypertext.h", + "ia2AccessibleText.h", + "ia2AccessibleTextSelectionContainer.h", + "ia2AccessibleValue.h", +] + +UNIFIED_SOURCES += [ + "ia2Accessible.cpp", + "ia2AccessibleAction.cpp", + "ia2AccessibleApplication.cpp", + "ia2AccessibleComponent.cpp", + "ia2AccessibleEditableText.cpp", + "ia2AccessibleHyperlink.cpp", + "ia2AccessibleHypertext.cpp", + "ia2AccessibleImage.cpp", + "ia2AccessibleRelation.cpp", + "ia2AccessibleText.cpp", + "ia2AccessibleTextSelectionContainer.cpp", + "ia2AccessibleValue.cpp", +] + +# These files cannot be built in unified mode because they both include +# AccessibleTable2_i.c. +SOURCES += [ + "ia2AccessibleTable.cpp", + "ia2AccessibleTableCell.cpp", +] + +LOCAL_INCLUDES += [ + "/accessible/base", + "/accessible/generic", + "/accessible/html", + "/accessible/windows", + "/accessible/windows/msaa", + "/accessible/xpcom", + "/accessible/xul", +] + +FINAL_LIBRARY = "xul" + +# The Windows MIDL code generator creates things like: +# +# #endif !_MIDL_USE_GUIDDEF_ +# +# which clang-cl complains about. MSVC doesn't, so turn this warning off. +if CONFIG["CC_TYPE"] == "clang-cl": + CXXFLAGS += ["-Wno-extra-tokens"] + +include("/ipc/chromium/chromium-config.mozbuild") |