STDMETHODIMP ia2Accessible::get_groupPosition(long* aGroupLevel, long* aSimilarItemsInGroup, long* aPositionInGroup) { if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup) return E_INVALIDARG; *aGroupLevel = 0; *aSimilarItemsInGroup = 0; *aPositionInGroup = 0; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; GroupPos groupPos = acc->GroupPosition(); // Group information for accessibles having level only (like html headings // elements) isn't exposed by this method. AT should look for 'level' object // attribute. if (!groupPos.setSize && !groupPos.posInSet) return S_FALSE; *aGroupLevel = groupPos.level; *aSimilarItemsInGroup = groupPos.setSize; *aPositionInGroup = groupPos.posInSet; return S_OK; }
STDMETHODIMP ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible, long* aCaretOffset) { if (!aAccessible || !aCaretOffset) return E_INVALIDARG; *aAccessible = nullptr; *aCaretOffset = -1; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; int32_t caretOffset = -1; Accessible* accWithCaret = SelectionMgr()->AccessibleWithCaret(&caretOffset); if (!accWithCaret || acc->Document() != accWithCaret->Document()) return S_FALSE; Accessible* child = accWithCaret; while (!child->IsDoc() && child != acc) child = child->Parent(); if (child != acc) return S_FALSE; *aAccessible = static_cast<IAccessible2*>( static_cast<AccessibleWrap*>(accWithCaret)); (*aAccessible)->AddRef(); *aCaretOffset = caretOffset; return S_OK; }
STDMETHODIMP ia2Accessible::get_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_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_windowHandle(HWND* aWindowHandle) { if (!aWindowHandle) return E_INVALIDARG; *aWindowHandle = 0; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; *aWindowHandle = AccessibleWrap::GetHWNDFor(acc); return S_OK; }
STDMETHODIMP 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::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_selectionRanges(IA2Range** aRanges, long *aNRanges) { if (!aRanges || !aNRanges) return E_INVALIDARG; *aNRanges = 0; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; AutoTArray<TextRange, 1> ranges; acc->Document()->SelectionRanges(&ranges); uint32_t len = ranges.Length(); for (uint32_t idx = 0; idx < len; idx++) { if (!ranges[idx].Crop(acc)) { ranges.RemoveElementAt(idx); } } *aNRanges = ranges.Length(); *aRanges = static_cast<IA2Range*>( ::CoTaskMemAlloc(sizeof(IA2Range) * *aNRanges)); if (!*aRanges) return E_OUTOFMEMORY; for (uint32_t idx = 0; idx < static_cast<uint32_t>(*aNRanges); idx++) { AccessibleWrap* anchor = static_cast<AccessibleWrap*>(ranges[idx].StartContainer()); (*aRanges)[idx].anchor = static_cast<IAccessible2*>(anchor); anchor->AddRef(); (*aRanges)[idx].anchorOffset = ranges[idx].StartOffset(); AccessibleWrap* active = static_cast<AccessibleWrap*>(ranges[idx].EndContainer()); (*aRanges)[idx].active = static_cast<IAccessible2*>(active); active->AddRef(); (*aRanges)[idx].activeOffset = ranges[idx].EndOffset(); } return S_OK; }
STDMETHODIMP ia2Accessible::get_locale(IA2Locale* aLocale) { if (!aLocale) return E_INVALIDARG; // Language codes consist of a primary code and a possibly empty series of // subcodes: language-code = primary-code ( "-" subcode )* // Two-letter primary codes are reserved for [ISO639] language abbreviations. // Any two-letter subcode is understood to be a [ISO3166] country code. AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; nsAutoString lang; acc->Language(lang); // If primary code consists from two letters then expose it as language. int32_t offset = lang.FindChar('-', 0); if (offset == -1) { if (lang.Length() == 2) { aLocale->language = ::SysAllocString(lang.get()); return S_OK; } } else if (offset == 2) { aLocale->language = ::SysAllocStringLen(lang.get(), 2); // If the first subcode consists from two letters then expose it as // country. offset = lang.FindChar('-', 3); if (offset == -1) { if (lang.Length() == 5) { aLocale->country = ::SysAllocString(lang.get() + 3); return S_OK; } } else if (offset == 5) { aLocale->country = ::SysAllocStringLen(lang.get() + 3, 2); } } // Expose as a string if primary code or subcode cannot point to language or // country abbreviations or if there are more than one subcode. aLocale->variant = ::SysAllocString(lang.get()); return S_OK; }
STDMETHODIMP ia2AccessibleComponent::get_foreground(IA2Color* aForeground) { A11Y_TRYBLOCK_BEGIN AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; nsIFrame* frame = acc->GetFrame(); if (frame) *aForeground = frame->StyleColor()->mColor; return S_OK; A11Y_TRYBLOCK_END }
STDMETHODIMP ia2AccessibleComponent::get_locationInParent(long* aX, long* aY) { A11Y_TRYBLOCK_BEGIN *aX = 0; *aY = 0; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; // If the object is not on any screen the returned position is (0,0). uint64_t state = acc->State(); if (state & states::INVISIBLE) return S_OK; int32_t x = 0, y = 0, width = 0, height = 0; nsresult rv = acc->GetBounds(&x, &y, &width, &height); if (NS_FAILED(rv)) return GetHRESULT(rv); Accessible* parentAcc = acc->Parent(); // 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 (!parentAcc) { *aX = x; *aY = y; return S_OK; } // The coordinates of the bounding box are given relative to the parent's // coordinate system. int32_t parentx = 0, parenty = 0; rv = acc->GetBounds(&parentx, &parenty, &width, &height); if (NS_FAILED(rv)) return GetHRESULT(rv); *aX = x - parentx; *aY = y - parenty; return S_OK; A11Y_TRYBLOCK_END }
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; }
const gchar * getDescriptionCB(AtkObject *aAtkObj) { AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); if (!accWrap || accWrap->IsDefunct()) return nsnull; /* nsIAccessible is responsible for the non-NULL description */ nsAutoString uniDesc; accWrap->Description(uniDesc); NS_ConvertUTF8toUTF16 objDesc(aAtkObj->description); if (!uniDesc.Equals(objDesc)) atk_object_set_description(aAtkObj, NS_ConvertUTF16toUTF8(uniDesc).get()); return aAtkObj->description; }
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 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; }
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; }
const gchar * getDescriptionCB(AtkObject *aAtkObj) { nsAutoString uniDesc; AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); if (accWrap) { if (accWrap->IsDefunct()) return nullptr; accWrap->Description(uniDesc); } else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) { proxy->Description(uniDesc); } else { return nullptr; } NS_ConvertUTF8toUTF16 objDesc(aAtkObj->description); if (!uniDesc.Equals(objDesc)) atk_object_set_description(aAtkObj, NS_ConvertUTF16toUTF8(uniDesc).get()); return aAtkObj->description; }