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; }
AtkRelationSet * refRelationSetCB(AtkObject *aAtkObj) { AtkRelationSet* relation_set = ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj); AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); if (!accWrap) return relation_set; // Keep in sync with AtkRelationType enum. static const uint32_t relationTypes[] = { nsIAccessibleRelation::RELATION_CONTROLLED_BY, nsIAccessibleRelation::RELATION_CONTROLLER_FOR, nsIAccessibleRelation::RELATION_LABEL_FOR, nsIAccessibleRelation::RELATION_LABELLED_BY, nsIAccessibleRelation::RELATION_MEMBER_OF, nsIAccessibleRelation::RELATION_NODE_CHILD_OF, nsIAccessibleRelation::RELATION_FLOWS_TO, nsIAccessibleRelation::RELATION_FLOWS_FROM, nsIAccessibleRelation::RELATION_SUBWINDOW_OF, nsIAccessibleRelation::RELATION_EMBEDS, nsIAccessibleRelation::RELATION_EMBEDDED_BY, nsIAccessibleRelation::RELATION_POPUP_FOR, nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF, nsIAccessibleRelation::RELATION_DESCRIBED_BY, nsIAccessibleRelation::RELATION_DESCRIPTION_FOR, nsIAccessibleRelation::RELATION_NODE_PARENT_OF }; for (uint32_t i = 0; i < ArrayLength(relationTypes); i++) { // Shift to 1 to skip ATK_RELATION_NULL. AtkRelationType atkType = static_cast<AtkRelationType>(i + 1); AtkRelation* atkRelation = atk_relation_set_get_relation_by_type(relation_set, atkType); if (atkRelation) atk_relation_set_remove(relation_set, atkRelation); Relation rel(accWrap->RelationByType(relationTypes[i])); nsTArray<AtkObject*> targets; Accessible* tempAcc = nullptr; while ((tempAcc = rel.Next())) targets.AppendElement(AccessibleWrap::GetAtkObject(tempAcc)); if (targets.Length()) { atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType); atk_relation_set_add(relation_set, atkRelation); g_object_unref(atkRelation); } } return relation_set; }
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; }
AtkRelationSet * refRelationSetCB(AtkObject *aAtkObj) { AtkRelationSet* relation_set = ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj); AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); if (!accWrap) return relation_set; PRUint32 relationTypes[] = { nsIAccessibleRelation::RELATION_LABELLED_BY, nsIAccessibleRelation::RELATION_LABEL_FOR, nsIAccessibleRelation::RELATION_NODE_CHILD_OF, nsIAccessibleRelation::RELATION_CONTROLLED_BY, nsIAccessibleRelation::RELATION_CONTROLLER_FOR, nsIAccessibleRelation::RELATION_EMBEDS, nsIAccessibleRelation::RELATION_FLOWS_TO, nsIAccessibleRelation::RELATION_FLOWS_FROM, nsIAccessibleRelation::RELATION_DESCRIBED_BY, nsIAccessibleRelation::RELATION_DESCRIPTION_FOR, }; for (PRUint32 i = 0; i < ArrayLength(relationTypes); i++) { AtkRelationType atkType = static_cast<AtkRelationType>(relationTypes[i]); AtkRelation* atkRelation = atk_relation_set_get_relation_by_type(relation_set, atkType); if (atkRelation) atk_relation_set_remove(relation_set, atkRelation); Relation rel(accWrap->RelationByType(relationTypes[i])); nsTArray<AtkObject*> targets; Accessible* tempAcc = nsnull; while ((tempAcc = rel.Next())) targets.AppendElement(AccessibleWrap::GetAtkObject(tempAcc)); if (targets.Length()) { atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType); atk_relation_set_add(relation_set, atkRelation); g_object_unref(atkRelation); } } return relation_set; }
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; }