STDMETHODIMP ia2Accessible::get_relations(long aMaxRelations, IAccessibleRelation** aRelation, long *aNRelations) { if (!aRelation || !aNRelations || aMaxRelations <= 0) return E_INVALIDARG; *aNRelations = 0; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; MOZ_ASSERT(!acc->IsProxy()); for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs) && *aNRelations < aMaxRelations; idx++) { if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; RelationType relationType = sRelationTypePairs[idx].first; Relation rel = acc->RelationByType(relationType); RefPtr<ia2AccessibleRelation> ia2Rel = new ia2AccessibleRelation(relationType, &rel); if (ia2Rel->HasTargets()) { ia2Rel.forget(aRelation + (*aNRelations)); (*aNRelations)++; } } return S_OK; }
STDMETHODIMP ia2Accessible::get_relation(long aRelationIndex, IAccessibleRelation** aRelation) { if (!aRelation || aRelationIndex < 0) return E_INVALIDARG; *aRelation = nullptr; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; MOZ_ASSERT(!acc->IsProxy()); long relIdx = 0; for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; RelationType relationType = sRelationTypePairs[idx].first; Relation rel = acc->RelationByType(relationType); RefPtr<ia2AccessibleRelation> ia2Relation = new ia2AccessibleRelation(relationType, &rel); if (ia2Relation->HasTargets()) { if (relIdx == aRelationIndex) { ia2Relation.forget(aRelation); return S_OK; } relIdx++; } } return E_INVALIDARG; }
STDMETHODIMP ia2Accessible::get_attributes(BSTR* aAttributes) { if (!aAttributes) return E_INVALIDARG; *aAttributes = nullptr; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; // The format is name:value;name:value; with \ for escaping these // characters ":;=,\". if (!acc->IsProxy()) { nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes(); return ConvertToIA2Attributes(attributes, aAttributes); } MOZ_ASSERT(!acc->IsProxy()); return E_UNEXPECTED; }
STDMETHODIMP ia2AccessibleValue::setCurrentValue(VARIANT aValue) { if (aValue.vt != VT_R8) return E_INVALIDARG; AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this); MOZ_ASSERT(!valueAcc->IsProxy()); if (valueAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; return valueAcc->SetCurValue(aValue.dblVal) ? S_OK : E_FAIL; }
// XXX Use MOZ_CAN_RUN_SCRIPT_BOUNDARY for now due to bug 1543294. MOZ_CAN_RUN_SCRIPT_BOUNDARY STDMETHODIMP ia2Accessible::scrollTo(enum IA2ScrollType aScrollType) { AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; MOZ_ASSERT(!acc->IsProxy()); RefPtr<PresShell> presShell = acc->Document()->PresShellPtr(); nsCOMPtr<nsIContent> content = acc->GetContent(); nsCoreUtils::ScrollTo(presShell, content, aScrollType); return S_OK; }
STDMETHODIMP ia2Accessible::scrollTo(enum IA2ScrollType aScrollType) { AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; MOZ_ASSERT(!acc->IsProxy()); nsCoreUtils::ScrollTo(acc->Document()->PresShell(), acc->GetContent(), aScrollType); return S_OK; }
STDMETHODIMP ia2Accessible::role(long* aRole) { if (!aRole) return E_INVALIDARG; *aRole = 0; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; #define ROLE(_geckoRole, stringRole, atkRole, macRole, \ msaaRole, ia2Role, androidClass, nameRule) \ case roles::_geckoRole: \ *aRole = ia2Role; \ break; a11y::role geckoRole; MOZ_ASSERT(!acc->IsProxy()); geckoRole = acc->Role(); switch (geckoRole) { #include "RoleMap.h" default: MOZ_CRASH("Unknown role."); } #undef ROLE // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call // the IA2 role a ROLE_OUTLINEITEM. MOZ_ASSERT(!acc->IsProxy()); if (geckoRole == roles::ROW) { Accessible* xpParent = acc->Parent(); if (xpParent && xpParent->Role() == roles::TREE_TABLE) *aRole = ROLE_SYSTEM_OUTLINEITEM; } return S_OK; }
STDMETHODIMP ia2Accessible::get_indexInParent(long* aIndexInParent) { if (!aIndexInParent) return E_INVALIDARG; *aIndexInParent = -1; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; MOZ_ASSERT(!acc->IsProxy()); *aIndexInParent = acc->IndexInParent(); if (*aIndexInParent == -1) return S_FALSE; return S_OK; }
STDMETHODIMP ia2Accessible::scrollToPoint(enum IA2CoordinateType aCoordType, long aX, long aY) { AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; MOZ_ASSERT(!acc->IsProxy()); acc->ScrollToPoint(geckoCoordType, aX, aY); return S_OK; }
STDMETHODIMP ia2Accessible::get_relationTargetsOfType(BSTR aType, long aMaxTargets, IUnknown*** aTargets, long* aNTargets) { if (!aTargets || !aNTargets || aMaxTargets < 0) return E_INVALIDARG; *aNTargets = 0; Maybe<RelationType> relationType; for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { if (wcscmp(aType, sRelationTypePairs[idx].second) == 0) { relationType.emplace(sRelationTypePairs[idx].first); break; } } if (!relationType) return E_INVALIDARG; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; nsTArray<Accessible*> targets; MOZ_ASSERT(!acc->IsProxy()); Relation rel = acc->RelationByType(*relationType); Accessible* target = nullptr; while ((target = rel.Next()) && static_cast<long>(targets.Length()) <= aMaxTargets) { targets.AppendElement(target); } *aNTargets = targets.Length(); *aTargets = static_cast<IUnknown**>( ::CoTaskMemAlloc(sizeof(IUnknown*) * *aNTargets)); if (!*aTargets) return E_OUTOFMEMORY; for (int32_t i = 0; i < *aNTargets; i++) { AccessibleWrap* target= static_cast<AccessibleWrap*>(targets[i]); (*aTargets)[i] = static_cast<IAccessible2*>(target); (*aTargets)[i]->AddRef(); } return S_OK; }
STDMETHODIMP ia2Accessible::get_states(AccessibleStates* aStates) { if (!aStates) return E_INVALIDARG; *aStates = 0; // XXX: bug 344674 should come with better approach that we have here. AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) { *aStates = IA2_STATE_DEFUNCT; return S_OK; } uint64_t state; MOZ_ASSERT(!acc->IsProxy()); state = acc->State(); if (state & states::INVALID) *aStates |= IA2_STATE_INVALID_ENTRY; if (state & states::REQUIRED) *aStates |= IA2_STATE_REQUIRED; // The following IA2 states are not supported by Gecko // IA2_STATE_ARMED // IA2_STATE_MANAGES_DESCENDANTS // IA2_STATE_ICONIFIED // IA2_STATE_INVALID // This is not a state, it is the absence of a state if (state & states::ACTIVE) *aStates |= IA2_STATE_ACTIVE; if (state & states::DEFUNCT) *aStates |= IA2_STATE_DEFUNCT; if (state & states::EDITABLE) *aStates |= IA2_STATE_EDITABLE; if (state & states::HORIZONTAL) *aStates |= IA2_STATE_HORIZONTAL; if (state & states::MODAL) *aStates |= IA2_STATE_MODAL; if (state & states::MULTI_LINE) *aStates |= IA2_STATE_MULTI_LINE; if (state & states::OPAQUE1) *aStates |= IA2_STATE_OPAQUE; if (state & states::SELECTABLE_TEXT) *aStates |= IA2_STATE_SELECTABLE_TEXT; if (state & states::SINGLE_LINE) *aStates |= IA2_STATE_SINGLE_LINE; if (state & states::STALE) *aStates |= IA2_STATE_STALE; if (state & states::SUPPORTS_AUTOCOMPLETION) *aStates |= IA2_STATE_SUPPORTS_AUTOCOMPLETION; if (state & states::TRANSIENT) *aStates |= IA2_STATE_TRANSIENT; if (state & states::VERTICAL) *aStates |= IA2_STATE_VERTICAL; if (state & states::CHECKED) *aStates |= IA2_STATE_CHECKABLE; if (state & states::PINNED) *aStates |= IA2_STATE_PINNED; return S_OK; }
STDMETHODIMP ia2Accessible::get_nRelations(long* aNRelations) { if (!aNRelations) return E_INVALIDARG; *aNRelations = 0; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; MOZ_ASSERT(!acc->IsProxy()); for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; Relation rel = acc->RelationByType(sRelationTypePairs[idx].first); if (rel.Next()) (*aNRelations)++; } return S_OK; }
STDMETHODIMP ia2AccessibleValue::get_minimumValue(VARIANT* aMinimumValue) { if (!aMinimumValue) return E_INVALIDARG; VariantInit(aMinimumValue); AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this); double minimumValue; MOZ_ASSERT(!valueAcc->IsProxy()); if (valueAcc->IsDefunct()) { return CO_E_OBJNOTCONNECTED; } minimumValue = valueAcc->MinValue(); if (IsNaN(minimumValue)) return S_FALSE; aMinimumValue->vt = VT_R8; aMinimumValue->dblVal = minimumValue; return S_OK; }