From 878d2906bcc829b52c67c415bb31898fbf8108ab Mon Sep 17 00:00:00 2001 From: Trevor Saunders Date: Mon, 9 Feb 2015 11:57:23 -0500 Subject: [PATCH] bug 1138436 - start on proxying IAccessible2 r=surkov, r=davidb --- accessible/ipc/ProxyAccessible.h | 3 + accessible/windows/ia2/ia2Accessible.cpp | 182 +++++++++++++++--- .../windows/ia2/ia2AccessibleRelation.h | 4 + accessible/windows/ia2/moz.build | 2 + 4 files changed, 162 insertions(+), 29 deletions(-) diff --git a/accessible/ipc/ProxyAccessible.h b/accessible/ipc/ProxyAccessible.h index 294922e84bf..dacad7442fc 100644 --- a/accessible/ipc/ProxyAccessible.h +++ b/accessible/ipc/ProxyAccessible.h @@ -42,6 +42,9 @@ public: uint32_t ChildrenCount() const { return mChildren.Length(); } ProxyAccessible* ChildAt(uint32_t aIdx) const { return mChildren[aIdx]; } + + // XXX evaluate if this is fast enough. + size_t IndexInParent() const { return mParent->mChildren.IndexOf(this); } bool MustPruneChildren() const; void Shutdown(); diff --git a/accessible/windows/ia2/ia2Accessible.cpp b/accessible/windows/ia2/ia2Accessible.cpp index 3d40fdab8f9..b708300f050 100644 --- a/accessible/windows/ia2/ia2Accessible.cpp +++ b/accessible/windows/ia2/ia2Accessible.cpp @@ -16,6 +16,7 @@ #include "IUnknownImpl.h" #include "nsCoreUtils.h" #include "nsIAccessibleTypes.h" +#include "mozilla/a11y/PDocAccessible.h" #include "Relation.h" #include "nsIPersistentProperties2.h" @@ -24,6 +25,8 @@ using namespace mozilla; using namespace mozilla::a11y; +template static void EscapeAttributeChars(String& aStr); + //////////////////////////////////////////////////////////////////////////////// // ia2Accessible //////////////////////////////////////////////////////////////////////////////// @@ -65,6 +68,15 @@ ia2Accessible::get_nRelations(long* aNRelations) if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + if (acc->IsProxy()) { + // XXX evaluate performance of collecting all relation targets. + nsTArray types; + nsTArray> targetSets; + acc->Proxy()->Relations(&types, &targetSets); + *aNRelations = types.Length(); + return S_OK; + } + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue; @@ -84,7 +96,7 @@ ia2Accessible::get_relation(long aRelationIndex, { A11Y_TRYBLOCK_BEGIN - if (!aRelation) + if (!aRelation || aRelationIndex < 0) return E_INVALIDARG; *aRelation = nullptr; @@ -92,6 +104,34 @@ ia2Accessible::get_relation(long aRelationIndex, if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + if (acc->IsProxy()) { + nsTArray types; + nsTArray> targetSets; + acc->Proxy()->Relations(&types, &targetSets); + + size_t targetSetCount = targetSets.Length(); + for (size_t i = 0; i < targetSetCount; i++) { + uint32_t relTypeIdx = static_cast(types[i]); + MOZ_ASSERT(sRelationTypePairs[relTypeIdx].first == types[i]); + if (sRelationTypePairs[relTypeIdx].second == IA2_RELATION_NULL) + continue; + + if (static_cast(aRelationIndex) == i) { + nsTArray> targets; + size_t targetCount = targetSets[i].Length(); + for (size_t j = 0; j < targetCount; j++) + targets.AppendElement(WrapperFor(targetSets[i][j])); + + nsRefPtr rel = + new ia2AccessibleRelation(types[i], Move(targets)); + rel.forget(aRelation); + return S_OK; + } + } + + return E_INVALIDARG; + } + long relIdx = 0; for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) { if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) @@ -123,7 +163,7 @@ ia2Accessible::get_relations(long aMaxRelations, { A11Y_TRYBLOCK_BEGIN - if (!aRelation || !aNRelations) + if (!aRelation || !aNRelations || aMaxRelations <= 0) return E_INVALIDARG; *aNRelations = 0; @@ -131,6 +171,34 @@ ia2Accessible::get_relations(long aMaxRelations, if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + if (acc->IsProxy()) { + nsTArray types; + nsTArray> targetSets; + acc->Proxy()->Relations(&types, &targetSets); + + size_t count = std::min(targetSets.Length(), + static_cast(aMaxRelations)); + size_t i = 0; + while (i < count) { + uint32_t relTypeIdx = static_cast(types[i]); + if (sRelationTypePairs[relTypeIdx].second == IA2_RELATION_NULL) + continue; + + size_t targetCount = targetSets[i].Length(); + nsTArray> targets(targetCount); + for (size_t j = 0; j < targetCount; j++) + targets.AppendElement(WrapperFor(targetSets[i][j])); + + nsRefPtr rel = + new ia2AccessibleRelation(types[i], Move(targets)); + rel.forget(aRelation + i); + i++; + } + + *aNRelations = i; + return S_OK; + } + for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs) && *aNRelations < aMaxRelations; idx++) { if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) @@ -169,7 +237,11 @@ ia2Accessible::role(long* aRole) *aRole = ia2Role; \ break; - a11y::role geckoRole = acc->Role(); + a11y::role geckoRole; + if (acc->IsProxy()) + geckoRole = acc->Proxy()->Role(); + else + geckoRole = acc->Role(); switch (geckoRole) { #include "RoleMap.h" default: @@ -180,10 +252,16 @@ ia2Accessible::role(long* aRole) // 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) + if (acc->IsProxy()) { + if (geckoRole == roles::ROW && acc->Proxy()->Parent() && + acc->Proxy()->Parent()->Role() == roles::TREE_TABLE) *aRole = ROLE_SYSTEM_OUTLINEITEM; + } else { + if (geckoRole == roles::ROW) { + Accessible* xpParent = acc->Parent(); + if (xpParent && xpParent->Role() == roles::TREE_TABLE) + *aRole = ROLE_SYSTEM_OUTLINEITEM; + } } return S_OK; @@ -274,7 +352,16 @@ ia2Accessible::get_states(AccessibleStates* aStates) // XXX: bug 344674 should come with better approach that we have here. AccessibleWrap* acc = static_cast(this); - uint64_t state = acc->State(); + if (acc->IsDefunct()) { + *aStates = IA2_STATE_DEFUNCT; + return CO_E_OBJNOTCONNECTED; + } + + uint64_t state; + if (acc->IsProxy()) + state = acc->Proxy()->State(); + else + state = acc->State(); if (state & states::INVALID) *aStates |= IA2_STATE_INVALID_ENTRY; @@ -446,7 +533,11 @@ ia2Accessible::get_indexInParent(long* aIndexInParent) if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; - *aIndexInParent = acc->IndexInParent(); + if (acc->IsProxy()) + *aIndexInParent = acc->Proxy()->IndexInParent(); + else + *aIndexInParent = acc->IndexInParent(); + if (*aIndexInParent == -1) return S_FALSE; @@ -521,8 +612,29 @@ ia2Accessible::get_attributes(BSTR* aAttributes) // The format is name:value;name:value; with \ for escaping these // characters ":;=,\". - nsCOMPtr attributes = acc->Attributes(); - return ConvertToIA2Attributes(attributes, aAttributes); + if (!acc->IsProxy()) { + nsCOMPtr attributes = acc->Attributes(); + return ConvertToIA2Attributes(attributes, aAttributes); + } + + nsTArray attrs; + acc->Proxy()->Attributes(&attrs); + nsString attrStr; + size_t attrCount = attrs.Length(); + for (size_t i = 0; i < attrCount; i++) { + EscapeAttributeChars(attrs[i].Name()); + EscapeAttributeChars(attrs[i].Value()); + AppendUTF8toUTF16(attrs[i].Name(), attrStr); + attrStr.Append(':'); + attrStr.Append(attrs[i].Value()); + attrStr.Append(';'); + } + + if (attrStr.IsEmpty()) + return S_FALSE; + + *aAttributes = ::SysAllocStringLen(attrStr.get(), attrStr.Length()); + return *aAttributes ? S_OK : E_OUTOFMEMORY; A11Y_TRYBLOCK_END } @@ -567,7 +679,7 @@ ia2Accessible::get_relationTargetsOfType(BSTR aType, { A11Y_TRYBLOCK_BEGIN - if (!aTargets || !aNTargets) + if (!aTargets || !aNTargets || aMaxTargets < 0) return E_INVALIDARG; *aNTargets = 0; @@ -585,13 +697,23 @@ ia2Accessible::get_relationTargetsOfType(BSTR aType, if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; - Relation rel = acc->RelationByType(*relationType); - nsTArray targets; - Accessible* target = nullptr; - while ((target = rel.Next()) && - static_cast(targets.Length()) <= aMaxTargets) - targets.AppendElement(target); + if (acc->IsProxy()) { + nsTArray targetProxies = + acc->Proxy()->RelationByType(*relationType); + + size_t targetCount = aMaxTargets; + if (targetProxies.Length() < targetCount) + targetCount = targetProxies.Length(); + for (size_t i = 0; i < targetCount; i++) + targets.AppendElement(WrapperFor(targetProxies[i])); + } else { + Relation rel = acc->RelationByType(*relationType); + Accessible* target = nullptr; + while ((target = rel.Next()) && + static_cast(targets.Length()) <= aMaxTargets) + targets.AppendElement(target); + } *aNTargets = targets.Length(); *aTargets = static_cast( @@ -613,6 +735,18 @@ ia2Accessible::get_relationTargetsOfType(BSTR aType, //////////////////////////////////////////////////////////////////////////////// // Helpers +template +static inline void +EscapeAttributeChars(String& aStr) +{ + int32_t offset = 0; + static const char kCharsToEscape[] = ":;=,\\"; + while ((offset = aStr.FindCharInSet(kCharsToEscape, offset)) != kNotFound) { + aStr.Insert('\\', offset); + offset += 2; + } +} + HRESULT ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes, BSTR* aIA2Attributes) @@ -632,8 +766,6 @@ ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes, nsAutoString strAttrs; - const char kCharsToEscape[] = ":;=,\\"; - bool hasMore = false; while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) { nsCOMPtr propSupports; @@ -647,21 +779,13 @@ ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes, if (NS_FAILED(propElem->GetKey(name))) return E_FAIL; - int32_t offset = 0; - while ((offset = name.FindCharInSet(kCharsToEscape, offset)) != kNotFound) { - name.Insert('\\', offset); - offset += 2; - } + EscapeAttributeChars(name); nsAutoString value; if (NS_FAILED(propElem->GetValue(value))) return E_FAIL; - offset = 0; - while ((offset = value.FindCharInSet(kCharsToEscape, offset)) != kNotFound) { - value.Insert('\\', offset); - offset += 2; - } + EscapeAttributeChars(value); AppendUTF8toUTF16(name, strAttrs); strAttrs.Append(':'); diff --git a/accessible/windows/ia2/ia2AccessibleRelation.h b/accessible/windows/ia2/ia2AccessibleRelation.h index 110a6436b64..e5ab6d25be8 100644 --- a/accessible/windows/ia2/ia2AccessibleRelation.h +++ b/accessible/windows/ia2/ia2AccessibleRelation.h @@ -24,6 +24,10 @@ class ia2AccessibleRelation MOZ_FINAL : public IAccessibleRelation public: ia2AccessibleRelation(RelationType aType, Relation* aRel); + ia2AccessibleRelation(RelationType aType, + nsTArray>&& aTargets) : + mType(aType), mTargets(Move(aTargets)) {} + // IUnknown DECL_IUNKNOWN diff --git a/accessible/windows/ia2/moz.build b/accessible/windows/ia2/moz.build index 02faea6fecb..1b444004318 100644 --- a/accessible/windows/ia2/moz.build +++ b/accessible/windows/ia2/moz.build @@ -52,3 +52,5 @@ if CONFIG['OS_ARCH'] == 'WINNT': DEFINES['NOMINMAX'] = True FAIL_ON_WARNINGS = True + +include('/ipc/chromium/chromium-config.mozbuild')