diff --git a/accessible/src/atk/nsApplicationAccessibleWrap.cpp b/accessible/src/atk/nsApplicationAccessibleWrap.cpp index 592776054a18..4d059cb70fd7 100644 --- a/accessible/src/atk/nsApplicationAccessibleWrap.cpp +++ b/accessible/src/atk/nsApplicationAccessibleWrap.cpp @@ -647,7 +647,8 @@ nsApplicationAccessibleWrap::AddRootAccessible(nsIAccessible *aRootAccWrap) AtkObject *atkAccessible = nsAccessibleWrap::GetAtkObject(aRootAccWrap); atk_object_set_parent(atkAccessible, mAtkObject); - PRUint32 count = mChildren.Count(); + PRUint32 count = 0; + mChildren->GetLength(&count); g_signal_emit_by_name(mAtkObject, "children_changed::add", count - 1, atkAccessible, NULL); @@ -669,27 +670,36 @@ nsApplicationAccessibleWrap::RemoveRootAccessible(nsIAccessible *aRootAccWrap) { NS_ENSURE_ARG_POINTER(aRootAccWrap); - PRInt32 index = mChildren.IndexOf(aRootAccWrap); + PRUint32 index = 0; + nsresult rv = NS_ERROR_FAILURE; + + // we must use weak ref to get the index + nsCOMPtr weakPtr = do_GetWeakReference(aRootAccWrap); + rv = mChildren->IndexOf(0, weakPtr, &index); AtkObject *atkAccessible = nsAccessibleWrap::GetAtkObject(aRootAccWrap); atk_object_set_parent(atkAccessible, NULL); g_signal_emit_by_name(mAtkObject, "children_changed::remove", index, atkAccessible, NULL); - nsresult rv = nsApplicationAccessible::RemoveRootAccessible(aRootAccWrap); - #ifdef MAI_LOGGING - PRUint32 count = mChildren.Count(); + PRUint32 count = 0; + mChildren->GetLength(&count); if (NS_SUCCEEDED(rv)) { + rv = mChildren->RemoveElementAt(index); MAI_LOG_DEBUG(("\nRemove RootAcc=%p, count=%d\n", (void*)aRootAccWrap, (count-1))); } else MAI_LOG_DEBUG(("\nFail to Remove RootAcc=%p, count=%d\n", (void*)aRootAccWrap, count)); -#endif +#else + NS_ENSURE_SUCCESS(rv, rv); + rv = mChildren->RemoveElementAt(index); +#endif + InvalidateChildren(); return rv; } diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index efe0f1e6f08b..6280ef672ab2 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -149,12 +149,14 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccessible) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsAccessible, nsAccessNode) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mChildren) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstChild) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNextSibling) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsAccessible, nsAccessNode) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent) - NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mChildren) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstChild) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNextSibling) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_ADDREF_INHERITED(nsAccessible, nsAccessNode) @@ -227,8 +229,8 @@ nsresult nsAccessible::QueryInterface(REFNSIID aIID, void** aInstancePtr) } nsAccessible::nsAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell): nsAccessNodeWrap(aNode, aShell), - mParent(nsnull), mRoleMapEntry(nsnull), - mAreChildrenInitialized(PR_FALSE) + mParent(nsnull), mFirstChild(nsnull), mNextSibling(nsnull), mRoleMapEntry(nsnull), + mAccChildCount(eChildCountUninitialized) { #ifdef NS_DEBUG_X { @@ -480,9 +482,39 @@ nsAccessible::GetKeyboardShortcut(nsAString& aAccessKey) return NS_OK; } +void +nsAccessible::SetParent(nsIAccessible *aParent) +{ + if (mParent != aParent) { + // Adopt a child -- we allow this now. the new parent + // may be a dom node which wasn't previously accessible but now is. + // The old parent's children now need to be invalidated, since + // it no longer owns the child, the new parent does + nsRefPtr oldParent = nsAccUtils::QueryAccessible(mParent); + if (oldParent) + oldParent->InvalidateChildren(); + } + + mParent = aParent; +} + +void +nsAccessible::SetFirstChild(nsIAccessible *aFirstChild) +{ + mFirstChild = aFirstChild; +} + +void +nsAccessible::SetNextSibling(nsIAccessible *aNextSibling) +{ + mNextSibling = aNextSibling; +} + nsresult nsAccessible::Shutdown() { + mNextSibling = nsnull; + // Invalidate the child count and pointers to other accessibles, also make // sure none of its children point to this parent InvalidateChildren(); @@ -495,112 +527,198 @@ nsAccessible::Shutdown() return nsAccessNodeWrap::Shutdown(); } +void +nsAccessible::InvalidateChildren() +{ + // Document has transformed, reset our invalid children and child count + + // Reset the sibling pointers, they will be set up again the next time + // CacheChildren() is called. + // Note: we don't want to start creating accessibles at this point, + // so don't use GetNextSibling() here. (bug 387252) + nsRefPtr child = nsAccUtils::QueryAccessible(mFirstChild); + while (child) { + child->mParent = nsnull; + + nsCOMPtr next = child->mNextSibling; + child->mNextSibling = nsnull; + child = nsAccUtils::QueryAccessible(next); + } + + mAccChildCount = eChildCountUninitialized; + mFirstChild = nsnull; +} + NS_IMETHODIMP nsAccessible::GetParent(nsIAccessible **aParent) { - NS_ENSURE_ARG_POINTER(aParent); + if (IsDefunct()) + return NS_ERROR_FAILURE; - NS_IF_ADDREF(*aParent = GetParent()); - return *aParent ? NS_OK : NS_ERROR_FAILURE; + nsCOMPtr cachedParent = GetCachedParent(); + if (cachedParent) { + cachedParent.swap(*aParent); + return NS_OK; + } + + nsCOMPtr docAccessible(GetDocAccessible()); + NS_ENSURE_TRUE(docAccessible, NS_ERROR_FAILURE); + + return docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE, aParent); +} + +already_AddRefed +nsAccessible::GetCachedParent() +{ + if (IsDefunct()) + return nsnull; + + nsCOMPtr cachedParent = mParent; + return cachedParent.forget(); +} + +already_AddRefed +nsAccessible::GetCachedFirstChild() +{ + if (IsDefunct()) + return nsnull; + + nsCOMPtr cachedFirstChild = mFirstChild; + return cachedFirstChild.forget(); } /* readonly attribute nsIAccessible nextSibling; */ -NS_IMETHODIMP -nsAccessible::GetNextSibling(nsIAccessible **aNextSibling) -{ - NS_ENSURE_ARG_POINTER(aNextSibling); +NS_IMETHODIMP nsAccessible::GetNextSibling(nsIAccessible * *aNextSibling) +{ + *aNextSibling = nsnull; + if (!mWeakShell) { + // This node has been shut down + return NS_ERROR_FAILURE; + } + if (!mParent) { + nsCOMPtr parent(GetParent()); + if (parent) { + PRInt32 numChildren; + parent->GetChildCount(&numChildren); // Make sure we cache all of the children + } + } - nsresult rv = NS_OK; - NS_IF_ADDREF(*aNextSibling = GetSiblingAtOffset(1, &rv)); - return rv; + if (mNextSibling || !mParent) { + // If no parent, don't try to calculate a new sibling + // It either means we're at the root or shutting down the parent + NS_IF_ADDREF(*aNextSibling = mNextSibling); + + return NS_OK; + } + + return NS_ERROR_FAILURE; } /* readonly attribute nsIAccessible previousSibling; */ -NS_IMETHODIMP -nsAccessible::GetPreviousSibling(nsIAccessible * *aPreviousSibling) +NS_IMETHODIMP nsAccessible::GetPreviousSibling(nsIAccessible * *aPreviousSibling) { - NS_ENSURE_ARG_POINTER(aPreviousSibling); + *aPreviousSibling = nsnull; - nsresult rv = NS_OK; - NS_IF_ADDREF(*aPreviousSibling = GetSiblingAtOffset(-1, &rv)); - return rv; + if (!mWeakShell) { + // This node has been shut down + return NS_ERROR_FAILURE; + } + + nsCOMPtr parent; + if (NS_FAILED(GetParent(getter_AddRefs(parent))) || !parent) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr testAccessible, prevSibling; + parent->GetFirstChild(getter_AddRefs(testAccessible)); + while (testAccessible && this != testAccessible) { + prevSibling = testAccessible; + prevSibling->GetNextSibling(getter_AddRefs(testAccessible)); + } + + if (!prevSibling) { + return NS_ERROR_FAILURE; + } + + NS_ADDREF(*aPreviousSibling = prevSibling); + return NS_OK; } /* readonly attribute nsIAccessible firstChild; */ -NS_IMETHODIMP -nsAccessible::GetFirstChild(nsIAccessible **aFirstChild) -{ - NS_ENSURE_ARG_POINTER(aFirstChild); - *aFirstChild = nsnull; - - if (gIsCacheDisabled) +NS_IMETHODIMP nsAccessible::GetFirstChild(nsIAccessible * *aFirstChild) +{ + if (gIsCacheDisabled) { InvalidateChildren(); + } + PRInt32 numChildren; + GetChildCount(&numChildren); // Make sure we cache all of the children - PRInt32 childCount = GetChildCount(); - NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE); +#ifdef DEBUG + nsRefPtr firstChild(nsAccUtils::QueryAccessible(mFirstChild)); + if (firstChild) { + nsCOMPtr realParent = firstChild->GetCachedParent(); + NS_ASSERTION(!realParent || realParent == this, + "Two accessibles have the same first child accessible."); + } +#endif - if (childCount > 0) - NS_ADDREF(*aFirstChild = GetChildAt(0)); + NS_IF_ADDREF(*aFirstChild = mFirstChild); - return NS_OK; + return NS_OK; } /* readonly attribute nsIAccessible lastChild; */ -NS_IMETHODIMP -nsAccessible::GetLastChild(nsIAccessible **aLastChild) -{ - NS_ENSURE_ARG_POINTER(aLastChild); - *aLastChild = nsnull; - - PRInt32 childCount = GetChildCount(); - NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE); - - NS_IF_ADDREF(*aLastChild = GetChildAt(childCount - 1)); +NS_IMETHODIMP nsAccessible::GetLastChild(nsIAccessible * *aLastChild) +{ + GetChildAt(-1, aLastChild); return NS_OK; } -NS_IMETHODIMP -nsAccessible::GetChildAt(PRInt32 aChildIndex, nsIAccessible **aChild) +NS_IMETHODIMP nsAccessible::GetChildAt(PRInt32 aChildNum, nsIAccessible **aChild) { - NS_ENSURE_ARG_POINTER(aChild); - *aChild = nsnull; + // aChildNum is a zero-based index - PRInt32 childCount = GetChildCount(); - NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE); + PRInt32 numChildren; + GetChildCount(&numChildren); - // If child index is negative, then return last child. - // XXX: do we really need this? - if (aChildIndex < 0) - aChildIndex = childCount - 1; + // If no children or aChildNum is larger than numChildren, return null + if (aChildNum >= numChildren || numChildren == 0 || !mWeakShell) { + *aChild = nsnull; + return NS_ERROR_FAILURE; + // If aChildNum is less than zero, set aChild to last index + } else if (aChildNum < 0) { + aChildNum = numChildren - 1; + } - nsIAccessible* child = GetChildAt(aChildIndex); - if (!child) - return NS_ERROR_INVALID_ARG; + nsCOMPtr current(mFirstChild), nextSibling; + PRInt32 index = 0; + + while (current) { + nextSibling = current; + if (++index > aChildNum) { + break; + } + nextSibling->GetNextSibling(getter_AddRefs(current)); + } + + NS_IF_ADDREF(*aChild = nextSibling); - NS_ADDREF(*aChild = child); return NS_OK; } // readonly attribute nsIArray children; -NS_IMETHODIMP -nsAccessible::GetChildren(nsIArray **aOutChildren) +NS_IMETHODIMP nsAccessible::GetChildren(nsIArray **aOutChildren) { - NS_ENSURE_ARG_POINTER(aOutChildren); *aOutChildren = nsnull; + nsCOMPtr children = do_CreateInstance(NS_ARRAY_CONTRACTID); + if (!children) + return NS_ERROR_FAILURE; - PRInt32 childCount = GetChildCount(); - NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE); - - nsresult rv = NS_OK; - nsCOMPtr children = - do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) { - nsIAccessible* child = GetChildAt(childIdx); - children->AppendElement(child, PR_FALSE); + nsCOMPtr curChild; + while (NextChild(curChild)) { + children->AppendElement(curChild, PR_FALSE); } - + NS_ADDREF(*aOutChildren = children); return NS_OK; } @@ -617,6 +735,39 @@ nsIAccessible *nsAccessible::NextChild(nsCOMPtr& aAccessible) return (aAccessible = nextChild); } +void nsAccessible::CacheChildren() +{ + if (!mWeakShell) { + // This node has been shut down + mAccChildCount = eChildCountUninitialized; + return; + } + + if (mAccChildCount == eChildCountUninitialized) { + mAccChildCount = 0;// Prevent reentry + PRBool allowsAnonChildren = GetAllowsAnonChildAccessibles(); + nsAccessibleTreeWalker walker(mWeakShell, mDOMNode, allowsAnonChildren); + // Seed the frame hint early while we're still on a container node. + // This is better than doing the GetPrimaryFrameFor() later on + // a text node, because text nodes aren't in the frame map. + walker.mState.frame = GetFrame(); + + nsRefPtr prevAcc; + PRInt32 childCount = 0; + walker.GetFirstChild(); + SetFirstChild(walker.mState.accessible); + + while (walker.mState.accessible) { + ++ childCount; + prevAcc = nsAccUtils::QueryAccessible(walker.mState.accessible); + prevAcc->SetParent(this); + walker.GetNextSibling(); + prevAcc->SetNextSibling(walker.mState.accessible); + } + mAccChildCount = childCount; + } +} + PRBool nsAccessible::GetAllowsAnonChildAccessibles() { @@ -624,23 +775,73 @@ nsAccessible::GetAllowsAnonChildAccessibles() } /* readonly attribute long childCount; */ -NS_IMETHODIMP -nsAccessible::GetChildCount(PRInt32 *aChildCount) +NS_IMETHODIMP nsAccessible::GetChildCount(PRInt32 *aAccChildCount) { - NS_ENSURE_ARG_POINTER(aChildCount); - - *aChildCount = GetChildCount(); - return *aChildCount != -1 ? NS_OK : NS_ERROR_FAILURE; + CacheChildren(); + *aAccChildCount = mAccChildCount; + return NS_OK; } /* readonly attribute long indexInParent; */ -NS_IMETHODIMP -nsAccessible::GetIndexInParent(PRInt32 *aIndexInParent) +NS_IMETHODIMP nsAccessible::GetIndexInParent(PRInt32 *aIndexInParent) { - NS_ENSURE_ARG_POINTER(aIndexInParent); + *aIndexInParent = -1; + if (!mWeakShell) { + return NS_ERROR_FAILURE; + } - *aIndexInParent = GetIndexInParent(); - return *aIndexInParent != -1 ? NS_OK : NS_ERROR_FAILURE; + nsCOMPtr parent; + GetParent(getter_AddRefs(parent)); + if (!parent) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr sibling; + parent->GetFirstChild(getter_AddRefs(sibling)); + if (!sibling) { + return NS_ERROR_FAILURE; + } + + *aIndexInParent = 0; + while (sibling != this) { + NS_ASSERTION(sibling, "Never ran into the same child that we started from"); + + if (!sibling) + return NS_ERROR_FAILURE; + + ++*aIndexInParent; + nsCOMPtr tempAccessible; + sibling->GetNextSibling(getter_AddRefs(tempAccessible)); + sibling = tempAccessible; + } + + return NS_OK; +} + +void +nsAccessible::TestChildCache(nsIAccessible *aCachedChild) +{ +#ifdef DEBUG_A11Y + // All cached accessible nodes should be in the parent + // It will assert if not all the children were created + // when they were first cached, and no invalidation + // ever corrected parent accessible's child cache. + if (mAccChildCount <= 0) + return; + + nsCOMPtr sibling = mFirstChild; + + while (sibling != aCachedChild) { + NS_ASSERTION(sibling, "[TestChildCache] Never ran into the same child that we started from"); + if (!sibling) + return; + + nsCOMPtr tempAccessible; + sibling->GetNextSibling(getter_AddRefs(tempAccessible)); + sibling = tempAccessible; + } + +#endif } nsresult nsAccessible::GetTranslatedString(const nsAString& aKey, nsAString& aStringOut) @@ -2912,247 +3113,8 @@ nsAccessible::GetNameInternal(nsAString& aName) return NS_OK; } -void -nsAccessible::SetParent(nsIAccessible *aParent) -{ - NS_PRECONDITION(aParent, "This method isn't used to set null parent!"); - - if (mParent && mParent != aParent) { - // Adopt a child -- we allow this now. the new parent - // may be a dom node which wasn't previously accessible but now is. - // The old parent's children now need to be invalidated, since - // it no longer owns the child, the new parent does - NS_ASSERTION(PR_FALSE, "Adopting child!"); - nsRefPtr oldParent = nsAccUtils::QueryAccessible(mParent); - if (oldParent) - oldParent->InvalidateChildren(); - } - - mParent = aParent; -} - -void -nsAccessible::InvalidateChildren() -{ - PRInt32 childCount = mChildren.Count(); - for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) { - nsRefPtr child = - nsAccUtils::QueryObject(mChildren.ObjectAt(childIdx)); - child->mParent = nsnull; - } - - mChildren.Clear(); - mAreChildrenInitialized = PR_FALSE; -} - -nsIAccessible* -nsAccessible::GetParent() -{ - if (IsDefunct()) - return nsnull; - - if (mParent) - return mParent; - - nsCOMPtr docAccessible(GetDocAccessible()); - NS_ASSERTION(docAccessible, "No document accessible for valid accessible!"); - - if (!docAccessible) - return nsnull; - - nsCOMPtr parent; - docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE, - getter_AddRefs(parent)); - -#ifdef DEBUG - nsRefPtr parentAcc = nsAccUtils::QueryAccessible(parent); - NS_ASSERTION(!parentAcc->IsDefunct(), "Defunct parent!"); - - parentAcc->EnsureChildren(); - if (parent != mParent) - NS_WARNING("Bad accessible tree!"); -#endif - - return parent; -} - -nsIAccessible* -nsAccessible::GetChildAt(PRUint32 aIndex) -{ - if (EnsureChildren()) - return nsnull; - - nsIAccessible *child = mChildren.SafeObjectAt(aIndex); - if (!child) - return nsnull; - -#ifdef DEBUG - nsRefPtr childAcc = nsAccUtils::QueryAccessible(child); - nsCOMPtr realParent = childAcc->mParent; - NS_ASSERTION(!realParent || realParent == this, - "Two accessibles have the same first child accessible!"); -#endif - - return child; -} - -PRInt32 -nsAccessible::GetChildCount() -{ - return EnsureChildren() ? -1 : mChildren.Count(); -} - -PRInt32 -nsAccessible::GetIndexOf(nsIAccessible *aChild) -{ - return EnsureChildren() ? -1 : mChildren.IndexOf(aChild); -} - -PRInt32 -nsAccessible::GetIndexInParent() -{ - nsIAccessible *parent = GetParent(); - if (!parent) - return -1; - - nsRefPtr parentAcc = - nsAccUtils::QueryObject(parent); - return parentAcc->GetIndexOf(this); -} - -already_AddRefed -nsAccessible::GetCachedParent() -{ - if (IsDefunct()) - return nsnull; - - nsCOMPtr cachedParent = mParent; - return cachedParent.forget(); -} - -already_AddRefed -nsAccessible::GetCachedFirstChild() -{ - if (IsDefunct()) - return nsnull; - - nsCOMPtr cachedFirstChild = GetChildAt(0); - return cachedFirstChild.forget(); -} - - //////////////////////////////////////////////////////////////////////////////// -// nsAccessible protected methods - -void -nsAccessible::CacheChildren() -{ - PRBool allowsAnonChildren = GetAllowsAnonChildAccessibles(); - nsAccessibleTreeWalker walker(mWeakShell, mDOMNode, allowsAnonChildren); - - // Seed the frame hint early while we're still on a container node. - // This is better than doing the GetPrimaryFrameFor() later on - // a text node, because text nodes aren't in the frame map. - walker.mState.frame = GetFrame(); - - walker.GetFirstChild(); - while (walker.mState.accessible) { - mChildren.AppendObject(walker.mState.accessible); - - nsRefPtr acc = - nsAccUtils::QueryObject(walker.mState.accessible); - acc->SetParent(this); - - walker.GetNextSibling(); - } -} - -void -nsAccessible::TestChildCache(nsIAccessible *aCachedChild) -{ -#ifdef DEBUG_A11Y - // All cached accessible nodes should be in the parent - // It will assert if not all the children were created - // when they were first cached, and no invalidation - // ever corrected parent accessible's child cache. - PRUint32 childCount = mChildren.Count(); - if (childCount == 0) { - NS_ASSERTION(mAreChildrenInitialized, - "Children are stored but not initailzied!"); - return; - } - - for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) { - nsIAccessible *child = GetChildAt(childIdx); - if (child == aCachedChild) - break; - } - - NS_ASSERTION(child == aCachedChild, - "[TestChildCache] cached accessible wasn't found. Wrong accessible tree!"); -#endif -} - -PRBool -nsAccessible::EnsureChildren() -{ - if (IsDefunct()) { - mAreChildrenInitialized = PR_FALSE; - return PR_TRUE; - } - - if (mAreChildrenInitialized) - return PR_FALSE; - - mAreChildrenInitialized = PR_TRUE; // Prevent reentry - CacheChildren(); - - return PR_FALSE; -} - -nsIAccessible* -nsAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError) -{ - if (IsDefunct()) { - if (aError) - *aError = NS_ERROR_FAILURE; - - return nsnull; - } - - nsIAccessible *parent = GetParent(); - if (!parent) { - if (aError) - *aError = NS_ERROR_UNEXPECTED; - - return nsnull; - } - - nsRefPtr parentAcc = - nsAccUtils::QueryObject(parent); - - PRInt32 indexInParent = parentAcc->GetIndexOf(this); - if (indexInParent == -1) { - if (aError) - *aError = NS_ERROR_UNEXPECTED; - - return nsnull; - } - - if (aError) { - PRInt32 childCount = parentAcc->GetChildCount(); - if (indexInParent + aOffset >= childCount) { - *aError = NS_OK; // fail peacefully - return nsnull; - } - } - - nsIAccessible *child = parentAcc->GetChildAt(indexInParent + aOffset); - if (aError && !child) - *aError = NS_ERROR_UNEXPECTED; - - return child; -} +// nsAccessible private methods already_AddRefed nsAccessible::GetFirstAvailableAccessible(nsIDOMNode *aStartNode) diff --git a/accessible/src/base/nsAccessible.h b/accessible/src/base/nsAccessible.h index f68c6c3beac7..ee5a49859179 100644 --- a/accessible/src/base/nsAccessible.h +++ b/accessible/src/base/nsAccessible.h @@ -103,11 +103,11 @@ private: #define NS_ACCESSIBLE_IMPL_CID \ -{ /* 07c5a6d6-4e87-4b57-8613-4c39e1b5150a */ \ - 0x07c5a6d6, \ - 0x4e87, \ - 0x4b57, \ - { 0x86, 0x13, 0x4c, 0x39, 0xe1, 0xb5, 0x15, 0x0a } \ +{ /* 53cfa871-be42-47fc-b416-0033653b3151 */ \ + 0x53cfa871, \ + 0xbe42, \ + 0x47fc, \ + { 0xb4, 0x16, 0x00, 0x33, 0x65, 0x3b, 0x31, 0x51 } \ } class nsAccessible : public nsAccessNodeWrap, @@ -199,7 +199,22 @@ public: nsIAccessible **aChild); ////////////////////////////////////////////////////////////////////////////// - // Initializing methods + // Initializing and cache methods + + /** + * Set accessible parent. + */ + void SetParent(nsIAccessible *aParent); + + /** + * Set first accessible child. + */ + void SetFirstChild(nsIAccessible *aFirstChild); + + /** + * Set next sibling accessible. + */ + void SetNextSibling(nsIAccessible *aNextSibling); /** * Set the ARIA role map entry for a new accessible. @@ -211,45 +226,10 @@ public: virtual void SetRoleMapEntry(nsRoleMapEntry *aRoleMapEntry); /** - * Set accessible parent. - */ - void SetParent(nsIAccessible *aParent); - - /** - * Set the child count to -1 (unknown) and null out cached child pointers. - * Should be called when accessible tree is changed because document has - * transformed. + * Set the child count to -1 (unknown) and null out cached child pointers */ virtual void InvalidateChildren(); - ////////////////////////////////////////////////////////////////////////////// - // Accessible tree traverse methods - - /** - * Return parent accessible. - */ - virtual nsIAccessible* GetParent(); - - /** - * Return child accessible at the given index. - */ - virtual nsIAccessible* GetChildAt(PRUint32 aIndex); - - /** - * Return child accessible count. - */ - virtual PRInt32 GetChildCount(); - - /** - * Return index of the given child accessible. - */ - virtual PRInt32 GetIndexOf(nsIAccessible *aChild); - - /** - * Return index in parent accessible. - */ - PRInt32 GetIndexInParent(); - /** * Return parent accessible only if cached. */ @@ -260,8 +240,13 @@ public: */ already_AddRefed GetCachedFirstChild(); + /** + * Assert if child not in parent's cache. + */ + void TestChildCache(nsIAccessible *aCachedChild); + ////////////////////////////////////////////////////////////////////////////// - // Miscellaneous methods + // Miscellaneous methods. /** * Fire accessible event. @@ -284,41 +269,22 @@ public: virtual nsresult AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32 aLength); + ////////////////////////////////////////////////////////////////////////////// + // Helper methods + + already_AddRefed GetParent() { + nsIAccessible *parent = nsnull; + GetParent(&parent); + return parent; + } + protected: - - ////////////////////////////////////////////////////////////////////////////// - // Initializing, cache and tree traverse methods - - /** - * Cache accessible children. - */ - virtual void CacheChildren(); - - /** - * Assert if child not in parent's cache. - */ - void TestChildCache(nsIAccessible *aCachedChild); - - /** - * Cache children if necessary. Return true if the accessible is defunct. - */ - PRBool EnsureChildren(); - - /** - * Return sibling accessible at the given offset. - */ - virtual nsIAccessible* GetSiblingAtOffset(PRInt32 aOffset, - nsresult* aError = nsnull); - - ////////////////////////////////////////////////////////////////////////////// - // Miscellaneous helpers - virtual nsIFrame* GetBoundsFrame(); virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame); PRBool IsVisible(PRBool *aIsOffscreen); ////////////////////////////////////////////////////////////////////////////// - // Name helpers + // Name helpers. /** * Compute the name of HTML node. @@ -334,6 +300,25 @@ protected: static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut); static nsresult GetTranslatedString(const nsAString& aKey, nsAString& aStringOut); + /** + * Walk into subtree and calculate the string which is used as the accessible + * name or description. + * + * @param aContent [in] traversed content + * @param aFlatString [in, out] result string + * @param aIsRootHidden [in] specifies whether root content (we started to + * traverse from) is hidden, in this case the result + * string is calculated from hidden children + * (this is used when hidden root content is explicitly + * specified as label or description by author) + */ + nsresult AppendFlatStringFromSubtreeRecurse(nsIContent *aContent, + nsAString *aFlatString, + PRBool aIsRootHidden); + + // Helpers for dealing with children + virtual void CacheChildren(); + // nsCOMPtr<>& is useful here, because getter_AddRefs() nulls the comptr's value, and NextChild // depends on the passed-in comptr being null or already set to a child (finding the next sibling). nsIAccessible *NextChild(nsCOMPtr& aAccessible); @@ -451,10 +436,11 @@ protected: // Data Members nsCOMPtr mParent; - nsCOMArray mChildren; - PRBool mAreChildrenInitialized; + nsCOMPtr mFirstChild; + nsCOMPtr mNextSibling; nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well + PRInt32 mAccChildCount; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsAccessible, diff --git a/accessible/src/base/nsApplicationAccessible.cpp b/accessible/src/base/nsApplicationAccessible.cpp index e2ec604f5fff..2af2b4e99678 100644 --- a/accessible/src/base/nsApplicationAccessible.cpp +++ b/accessible/src/base/nsApplicationAccessible.cpp @@ -42,22 +42,64 @@ #include "nsApplicationAccessible.h" -#include "nsAccessibilityService.h" - #include "nsIComponentManager.h" #include "nsServiceManagerUtils.h" -nsApplicationAccessible::nsApplicationAccessible() : - nsAccessibleWrap(nsnull, nsnull) +nsApplicationAccessible::nsApplicationAccessible(): + nsAccessibleWrap(nsnull, nsnull), mChildren(nsnull) { } //////////////////////////////////////////////////////////////////////////////// // nsISupports -NS_IMPL_ISUPPORTS_INHERITED0(nsApplicationAccessible, nsAccessible) +NS_IMPL_CYCLE_COLLECTION_CLASS(nsApplicationAccessible) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsApplicationAccessible, + nsAccessible) + + nsCOMPtr enumerator; + tmp->mChildren->Enumerate(getter_AddRefs(enumerator)); + + nsCOMPtr childWeakRef; + nsCOMPtr accessible; + + PRBool hasMoreElements; + while(NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) + && hasMoreElements) { + + enumerator->GetNext(getter_AddRefs(childWeakRef)); + accessible = do_QueryReferent(childWeakRef); + if (accessible) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "nsApplicationAccessible child"); + cb.NoteXPCOMChild(accessible); + } + } + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsApplicationAccessible, + nsAccessible) + tmp->mChildren->Clear(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsApplicationAccessible) +NS_INTERFACE_MAP_END_INHERITING(nsAccessible) + +NS_IMPL_ADDREF_INHERITED(nsApplicationAccessible, nsAccessible) +NS_IMPL_RELEASE_INHERITED(nsApplicationAccessible, nsAccessible) //////////////////////////////////////////////////////////////////////////////// +// nsIAccessNode + +nsresult +nsApplicationAccessible::Init() +{ + nsresult rv; + mChildren = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + return rv; +} + // nsIAccessible NS_IMETHODIMP @@ -88,67 +130,19 @@ nsApplicationAccessible::GetName(nsAString& aName) return NS_OK; } -NS_IMETHODIMP -nsApplicationAccessible::GetDescription(nsAString& aValue) +nsresult +nsApplicationAccessible::GetRoleInternal(PRUint32 *aRole) { - aValue.Truncate(); + *aRole = nsIAccessibleRole::ROLE_APP_ROOT; return NS_OK; } NS_IMETHODIMP nsApplicationAccessible::GetRole(PRUint32 *aRole) { - NS_ENSURE_ARG_POINTER(aRole); - return GetRoleInternal(aRole); } -NS_IMETHODIMP -nsApplicationAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState) -{ - NS_ENSURE_ARG_POINTER(aState); - *aState = 0; - - if (aExtraState) - *aExtraState = 0; - - return NS_OK; -} - -NS_IMETHODIMP -nsApplicationAccessible::GetParent(nsIAccessible **aAccessible) -{ - NS_ENSURE_ARG_POINTER(aAccessible); - *aAccessible = nsnull; - - return IsDefunct() ? NS_ERROR_FAILURE : NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsAccessNode public methods - -PRBool -nsApplicationAccessible::IsDefunct() -{ - return nsAccessibilityService::gIsShutdown; -} - -nsresult -nsApplicationAccessible::Init() -{ - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsAccessible public methods - -nsresult -nsApplicationAccessible::GetRoleInternal(PRUint32 *aRole) -{ - *aRole = nsIAccessibleRole::ROLE_APP_ROOT; - return NS_OK; -} - nsresult nsApplicationAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState) @@ -160,59 +154,124 @@ nsApplicationAccessible::GetStateInternal(PRUint32 *aState, return NS_OK; } -nsIAccessible* -nsApplicationAccessible::GetParent() +NS_IMETHODIMP +nsApplicationAccessible::GetParent(nsIAccessible **aParent) { - return nsnull; + *aParent = nsnull; + return NS_OK; } -void -nsApplicationAccessible::InvalidateChildren() +NS_IMETHODIMP +nsApplicationAccessible::GetChildAt(PRInt32 aChildNum, nsIAccessible **aChild) { - // Do nothing because application children are kept updated by - // AddRootAccessible() and RemoveRootAccessible() method calls. + NS_ENSURE_ARG_POINTER(aChild); + *aChild = nsnull; + + PRUint32 count = 0; + nsresult rv = NS_OK; + + if (mChildren) { + rv = mChildren->GetLength(&count); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (aChildNum >= static_cast(count) || count == 0) + return NS_ERROR_INVALID_ARG; + + if (aChildNum < 0) + aChildNum = count - 1; + + nsCOMPtr childWeakRef; + rv = mChildren->QueryElementAt(aChildNum, NS_GET_IID(nsIWeakReference), + getter_AddRefs(childWeakRef)); + NS_ENSURE_SUCCESS(rv, rv); + + if (childWeakRef) { + nsCOMPtr childAcc(do_QueryReferent(childWeakRef)); + NS_IF_ADDREF(*aChild = childAcc); + } + + return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsAccessible protected methods +NS_IMETHODIMP +nsApplicationAccessible::GetNextSibling(nsIAccessible **aNextSibling) +{ + NS_ENSURE_ARG_POINTER(aNextSibling); + + *aNextSibling = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +nsApplicationAccessible::GetPreviousSibling(nsIAccessible **aPreviousSibling) +{ + NS_ENSURE_ARG_POINTER(aPreviousSibling); + + *aPreviousSibling = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +nsApplicationAccessible::GetIndexInParent(PRInt32 *aIndexInParent) +{ + NS_ENSURE_ARG_POINTER(aIndexInParent); + + *aIndexInParent = -1; + return NS_OK; +} void nsApplicationAccessible::CacheChildren() { - // Nothing to do. Children are keeped up to dated by Add/RemoveRootAccessible - // method calls. -} - -nsIAccessible* -nsApplicationAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError) -{ - if (IsDefunct()) { - if (aError) - *aError = NS_ERROR_FAILURE; - - return nsnull; + if (!mChildren) { + mAccChildCount = eChildCountUninitialized; + return; } - if (aError) - *aError = NS_OK; // fail peacefully + if (mAccChildCount == eChildCountUninitialized) { + mAccChildCount = 0;// Prevent reentry + nsCOMPtr enumerator; + mChildren->Enumerate(getter_AddRefs(enumerator)); - return nsnull; + nsCOMPtr childWeakRef; + nsCOMPtr accessible; + nsRefPtr prevAcc; + PRBool hasMoreElements; + + while(NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) && + hasMoreElements) { + enumerator->GetNext(getter_AddRefs(childWeakRef)); + accessible = do_QueryReferent(childWeakRef); + if (accessible) { + if (prevAcc) + prevAcc->SetNextSibling(accessible); + else + SetFirstChild(accessible); + + prevAcc = nsAccUtils::QueryAccessible(accessible); + prevAcc->SetParent(this); + } + } + + PRUint32 count = 0; + mChildren->GetLength(&count); + mAccChildCount = static_cast(count); + } } -//////////////////////////////////////////////////////////////////////////////// -// Public methods +// nsApplicationAccessible nsresult nsApplicationAccessible::AddRootAccessible(nsIAccessible *aRootAccessible) { NS_ENSURE_ARG_POINTER(aRootAccessible); - if (!mChildren.AppendObject(aRootAccessible)) - return NS_ERROR_FAILURE; - - nsRefPtr rootAcc = nsAccUtils::QueryAccessible(aRootAccessible); - rootAcc->SetParent(this); + // add by weak reference + nsresult rv = mChildren->AppendElement(aRootAccessible, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + InvalidateChildren(); return NS_OK; } @@ -221,8 +280,17 @@ nsApplicationAccessible::RemoveRootAccessible(nsIAccessible *aRootAccessible) { NS_ENSURE_ARG_POINTER(aRootAccessible); - // It's not needed to void root accessible parent because this method is - // called on root accessible shutdown and its parent will be cleared - // properly. - return mChildren.RemoveObject(aRootAccessible) ? NS_OK : NS_ERROR_FAILURE; + PRUint32 index = 0; + + // we must use weak ref to get the index + nsCOMPtr weakPtr = do_GetWeakReference(aRootAccessible); + nsresult rv = mChildren->IndexOf(0, weakPtr, &index); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mChildren->RemoveElementAt(index); + NS_ENSURE_SUCCESS(rv, rv); + + InvalidateChildren(); + return NS_OK; } + diff --git a/accessible/src/base/nsApplicationAccessible.h b/accessible/src/base/nsApplicationAccessible.h index 6668df5708bc..e45898e8e558 100644 --- a/accessible/src/base/nsApplicationAccessible.h +++ b/accessible/src/base/nsApplicationAccessible.h @@ -63,36 +63,34 @@ public: // nsISupports NS_DECL_ISUPPORTS_INHERITED - - // nsIAccessible - NS_IMETHOD GetName(nsAString& aName); - NS_IMETHOD GetDescription(nsAString& aValue); - NS_IMETHOD GetRole(PRUint32 *aRole); - NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState); - - NS_IMETHOD GetParent(nsIAccessible **aAccessible); + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsApplicationAccessible, + nsAccessible) // nsAccessNode - virtual PRBool IsDefunct(); virtual nsresult Init(); + // nsIAccessible + NS_IMETHOD GetName(nsAString & aName); + NS_IMETHOD GetRole(PRUint32 *aRole); + NS_IMETHOD GetParent(nsIAccessible * *aParent); + NS_IMETHOD GetNextSibling(nsIAccessible * *aNextSibling); + NS_IMETHOD GetPreviousSibling(nsIAccessible **aPreviousSibling); + NS_IMETHOD GetIndexInParent(PRInt32 *aIndexInParent); + NS_IMETHOD GetChildAt(PRInt32 aChildNum, nsIAccessible **aChild); + // nsAccessible virtual nsresult GetRoleInternal(PRUint32 *aRole); virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState); - virtual nsIAccessible* GetParent(); - - virtual void InvalidateChildren(); // nsApplicationAccessible virtual nsresult AddRootAccessible(nsIAccessible *aRootAccWrap); virtual nsresult RemoveRootAccessible(nsIAccessible *aRootAccWrap); protected: - // nsAccessible virtual void CacheChildren(); - virtual nsIAccessible* GetSiblingAtOffset(PRInt32 aOffset, - nsresult *aError = nsnull); + + nsCOMPtr mChildren; }; #endif diff --git a/accessible/src/base/nsBaseWidgetAccessible.cpp b/accessible/src/base/nsBaseWidgetAccessible.cpp index eea11a3e0b29..5bd4d105ca3d 100644 --- a/accessible/src/base/nsBaseWidgetAccessible.cpp +++ b/accessible/src/base/nsBaseWidgetAccessible.cpp @@ -65,9 +65,7 @@ nsAccessibleWrap(aNode, aShell) NS_IMPL_ISUPPORTS_INHERITED0(nsLeafAccessible, nsAccessible) -//////////////////////////////////////////////////////////////////////////////// -// nsLeafAccessible: nsAccessible public - +// nsAccessible::GetChildAtPoint() nsresult nsLeafAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, PRBool aDeepestChild, @@ -78,13 +76,12 @@ nsLeafAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsLeafAccessible: nsAccessible private - +// nsAccessible::CacheChildren() void nsLeafAccessible::CacheChildren() { // No children for leaf accessible. + mAccChildCount = IsDefunct() ? eChildCountUninitialized : 0; } diff --git a/accessible/src/base/nsCoreUtils.cpp b/accessible/src/base/nsCoreUtils.cpp index 0b32085ad579..3d5a88d2e222 100644 --- a/accessible/src/base/nsCoreUtils.cpp +++ b/accessible/src/base/nsCoreUtils.cpp @@ -1027,7 +1027,7 @@ nsCoreUtils::GetLastSensibleColumn(nsITreeBoxObject *aTree) } PRUint32 -nsCoreUtils::GetSensibleColumnCount(nsITreeBoxObject *aTree) +nsCoreUtils::GetSensiblecolumnCount(nsITreeBoxObject *aTree) { PRUint32 count = 0; diff --git a/accessible/src/base/nsCoreUtils.h b/accessible/src/base/nsCoreUtils.h index 1eb7a2ee693b..4fa693ad2a9a 100644 --- a/accessible/src/base/nsCoreUtils.h +++ b/accessible/src/base/nsCoreUtils.h @@ -413,7 +413,7 @@ public: /** * Return sensible columns count for the given tree box object. */ - static PRUint32 GetSensibleColumnCount(nsITreeBoxObject *aTree); + static PRUint32 GetSensiblecolumnCount(nsITreeBoxObject *aTree); /** * Return sensible column at the given index for the given tree box object. diff --git a/accessible/src/base/nsDocAccessible.cpp b/accessible/src/base/nsDocAccessible.cpp index 276a8d745f93..15f30508ad3d 100644 --- a/accessible/src/base/nsDocAccessible.cpp +++ b/accessible/src/base/nsDocAccessible.cpp @@ -73,16 +73,16 @@ #include "nsIXULDocument.h" #endif -//////////////////////////////////////////////////////////////////////////////// -// Static member initialization +//=============================// +// nsDocAccessible // +//=============================// PRUint32 nsDocAccessible::gLastFocusedAccessiblesState = 0; nsIAtom *nsDocAccessible::gLastFocusedFrameType = nsnull; - -//////////////////////////////////////////////////////////////////////////////// -// Constructor/desctructor - +//----------------------------------------------------- +// construction +//----------------------------------------------------- nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell): nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull), mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE), @@ -129,13 +129,15 @@ nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell) } } +//----------------------------------------------------- +// destruction +//----------------------------------------------------- nsDocAccessible::~nsDocAccessible() { } - //////////////////////////////////////////////////////////////////////////////// -// nsISupports +// nsDocAccessible. nsISupports static PLDHashOperator ElementTraverser(const void *aKey, nsIAccessNode *aAccessNode, @@ -180,10 +182,6 @@ NS_INTERFACE_MAP_END_INHERITING(nsHyperTextAccessible) NS_IMPL_ADDREF_INHERITED(nsDocAccessible, nsHyperTextAccessible) NS_IMPL_RELEASE_INHERITED(nsDocAccessible, nsHyperTextAccessible) - -//////////////////////////////////////////////////////////////////////////////// -// nsIAccessible - NS_IMETHODIMP nsDocAccessible::GetName(nsAString& aName) { @@ -206,7 +204,6 @@ nsDocAccessible::GetName(nsAString& aName) return rv; } -// nsAccessible public method nsresult nsDocAccessible::GetRoleInternal(PRUint32 *aRole) { @@ -245,7 +242,6 @@ nsDocAccessible::GetRoleInternal(PRUint32 *aRole) return NS_OK; } -// nsAccessible public method void nsDocAccessible::SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry) { @@ -286,7 +282,6 @@ nsDocAccessible::GetDescription(nsAString& aDescription) return NS_OK; } -// nsAccessible public method nsresult nsDocAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState) { @@ -337,7 +332,6 @@ nsDocAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState) return NS_OK; } -// nsAccessible public method nsresult nsDocAccessible::GetARIAState(PRUint32 *aState, PRUint32 *aExtraState) { @@ -402,9 +396,7 @@ NS_IMETHODIMP nsDocAccessible::TakeFocus() return NS_ERROR_FAILURE; } - -//////////////////////////////////////////////////////////////////////////////// -// nsIAccessibleDocument +// ------- nsIAccessibleDocument Methods (5) --------------- NS_IMETHODIMP nsDocAccessible::GetURL(nsAString& aURL) { @@ -507,7 +499,6 @@ NS_IMETHODIMP nsDocAccessible::GetDocument(nsIDOMDocument **aDOMDoc) return NS_ERROR_FAILURE; } -// nsIAccessibleHyperText method NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor) { NS_ENSURE_ARG_POINTER(aEditor); @@ -566,7 +557,6 @@ NS_IMETHODIMP nsDocAccessible::GetCachedAccessNode(void *aUniqueID, nsIAccessNod return NS_OK; } -// nsDocAccessible public method void nsDocAccessible::CacheAccessNode(void *aUniqueID, nsIAccessNode *aAccessNode) { @@ -584,7 +574,6 @@ nsDocAccessible::CacheAccessNode(void *aUniqueID, nsIAccessNode *aAccessNode) PutCacheEntry(mAccessNodeCache, aUniqueID, aAccessNode); } -// nsDocAccessible public method void nsDocAccessible::RemoveAccessNodeFromCache(nsIAccessNode *aAccessNode) { @@ -596,8 +585,31 @@ nsDocAccessible::RemoveAccessNodeFromCache(nsIAccessNode *aAccessNode) mAccessNodeCache.Remove(uniqueID); } -//////////////////////////////////////////////////////////////////////////////// -// nsAccessNode +NS_IMETHODIMP nsDocAccessible::GetParent(nsIAccessible **aParent) +{ + // Hook up our new accessible with our parent + *aParent = nsnull; + NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE); + if (!mParent) { + nsIDocument *parentDoc = mDocument->GetParentDocument(); + NS_ENSURE_TRUE(parentDoc, NS_ERROR_FAILURE); + nsIContent *ownerContent = parentDoc->FindContentForSubDocument(mDocument); + nsCOMPtr ownerNode(do_QueryInterface(ownerContent)); + if (ownerNode) { + nsCOMPtr accService = + do_GetService("@mozilla.org/accessibilityService;1"); + if (accService) { + // XXX aaronl: ideally we would traverse the presshell chain + // Since there's no easy way to do that, we cheat and use + // the document hierarchy. GetAccessibleFor() is bad because + // it doesn't support our concept of multiple presshells per doc. + // It should be changed to use GetAccessibleInWeakShell() + accService->GetAccessibleFor(ownerNode, getter_AddRefs(mParent)); + } + } + } + return mParent ? nsAccessible::GetParent(aParent) : NS_ERROR_FAILURE; +} nsresult nsDocAccessible::Init() @@ -606,7 +618,8 @@ nsDocAccessible::Init() AddEventListeners(); - GetParent(); // Ensure outer doc mParent accessible. + nsCOMPtr parentAccessible; // Ensure outer doc mParent accessible + GetParent(getter_AddRefs(parentAccessible)); nsresult rv = nsHyperTextAccessibleWrap::Init(); NS_ENSURE_SUCCESS(rv, rv); @@ -667,7 +680,6 @@ nsDocAccessible::Shutdown() return NS_OK; } -// nsDocAccessible protected member void nsDocAccessible::ShutdownChildDocuments(nsIDocShellTreeItem *aStart) { nsCOMPtr treeNode(do_QueryInterface(aStart)); @@ -713,7 +725,6 @@ nsDocAccessible::IsDefunct() return !mDocument; } -// nsDocAccessible protected member void nsDocAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aRelativeFrame) { *aRelativeFrame = GetFrame(); @@ -757,7 +768,7 @@ void nsDocAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aRelativeFrame) } } -// nsDocAccessible protected member + nsresult nsDocAccessible::AddEventListeners() { // 1) Set up scroll position listener @@ -803,7 +814,6 @@ nsresult nsDocAccessible::AddEventListeners() return NS_OK; } -// nsDocAccessible protected member nsresult nsDocAccessible::RemoveEventListeners() { // Remove listeners associated with content documents @@ -850,7 +860,6 @@ nsresult nsDocAccessible::RemoveEventListeners() return NS_OK; } -// nsDocAccessible public member void nsDocAccessible::FireDocLoadEvents(PRUint32 aEventType) { @@ -880,7 +889,8 @@ nsDocAccessible::FireDocLoadEvents(PRUint32 aEventType) if (isFinished) { // Need to wait until scrollable view is available AddScrollListener(); - nsRefPtr acc(nsAccUtils::QueryAccessible(GetParent())); + nsCOMPtr parent(nsAccessible::GetParent()); + nsRefPtr acc(nsAccUtils::QueryAccessible(parent)); if (acc) { // Make the parent forget about the old document as a child acc->InvalidateChildren(); @@ -944,7 +954,6 @@ void nsDocAccessible::ScrollTimerCallback(nsITimer *aTimer, void *aClosure) } } -// nsDocAccessible protected member void nsDocAccessible::AddScrollListener() { nsCOMPtr presShell(do_QueryReferent(mWeakShell)); @@ -961,7 +970,6 @@ void nsDocAccessible::AddScrollListener() scrollableView->AddScrollPositionListener(this); } -// nsDocAccessible protected member void nsDocAccessible::RemoveScrollListener() { nsCOMPtr presShell(do_QueryReferent(mWeakShell)); @@ -978,9 +986,6 @@ void nsDocAccessible::RemoveScrollListener() scrollableView->RemoveScrollPositionListener(this); } -//////////////////////////////////////////////////////////////////////////////// -// nsIScrollPositionListener - NS_IMETHODIMP nsDocAccessible::ScrollPositionWillChange(nsIScrollableView *aView, nscoord aX, nscoord aY) { return NS_OK; @@ -1007,9 +1012,6 @@ NS_IMETHODIMP nsDocAccessible::ScrollPositionDidChange(nsIScrollableView *aScrol return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsIObserver - NS_IMETHODIMP nsDocAccessible::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData) { @@ -1024,7 +1026,7 @@ NS_IMETHODIMP nsDocAccessible::Observe(nsISupports *aSubject, const char *aTopic return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////// // nsIDocumentObserver NS_IMPL_NSIDOCUMENTOBSERVER_CORE_STUB(nsDocAccessible) @@ -1060,7 +1062,7 @@ nsDocAccessible::AttributeChanged(nsIDocument *aDocument, nsIContent* aContent, } } -// nsDocAccessible protected member + void nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID, nsIAtom* aAttribute) { @@ -1211,7 +1213,6 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID } } -// nsDocAccessible protected member void nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute) { @@ -1361,7 +1362,6 @@ void nsDocAccessible::ContentAppended(nsIDocument *aDocument, } } - void nsDocAccessible::ContentStatesChanged(nsIDocument* aDocument, nsIContent* aContent1, nsIContent* aContent2, @@ -1417,45 +1417,6 @@ nsDocAccessible::ParentChainChanged(nsIContent *aContent) { } - -//////////////////////////////////////////////////////////////////////////////// -// nsAccessible - -nsIAccessible* -nsDocAccessible::GetParent() -{ - if (IsDefunct()) - return nsnull; - - if (mParent) - return mParent; - - nsIDocument* parentDoc = mDocument->GetParentDocument(); - if (!parentDoc) - return nsnull; - - nsIContent* ownerContent = parentDoc->FindContentForSubDocument(mDocument); - nsCOMPtr ownerNode(do_QueryInterface(ownerContent)); - if (ownerNode) { - nsCOMPtr accService = GetAccService(); - if (accService) { - // XXX aaronl: ideally we would traverse the presshell chain. Since - // there's no easy way to do that, we cheat and use the document - // hierarchy. GetAccessibleFor() is bad because it doesn't support our - // concept of multiple presshells per doc. - // It should be changed to use GetAccessibleInWeakShell() - accService->GetAccessibleFor(ownerNode, getter_AddRefs(mParent)); - } - } - - NS_ASSERTION(mParent, "No parent for not root document accessible!"); - return mParent; -} - - -//////////////////////////////////////////////////////////////////////////////// -// Protected members - void nsDocAccessible::FireValueChangeForTextFields(nsIAccessible *aPossibleTextFieldAccessible) { @@ -1610,8 +1571,7 @@ nsDocAccessible::CreateTextChangeEventForNode(nsIAccessible *aContainerAccessibl return event; } - -// nsDocAccessible public member + nsresult nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode, @@ -1625,7 +1585,6 @@ nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType, return FireDelayedAccessibleEvent(event); } -// nsDocAccessible public member nsresult nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent) { @@ -1994,7 +1953,6 @@ void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode) mAccessNodeCache.Remove(uniqueID); } -// nsDocAccessible public member void nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild, PRUint32 aChangeType) @@ -2222,7 +2180,6 @@ nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild, FireDelayedAccessibleEvent(reorderEvent); } -// nsIAccessibleDocument method NS_IMETHODIMP nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode, PRBool aCanCreate, diff --git a/accessible/src/base/nsDocAccessible.h b/accessible/src/base/nsDocAccessible.h index d351be665a16..7926dccd90f7 100644 --- a/accessible/src/base/nsDocAccessible.h +++ b/accessible/src/base/nsDocAccessible.h @@ -87,6 +87,7 @@ public: NS_IMETHOD GetDescription(nsAString& aDescription); NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes); NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild); + NS_IMETHOD GetParent(nsIAccessible **aParent); NS_IMETHOD TakeFocus(void); // nsIScrollPositionListener @@ -110,9 +111,7 @@ public: virtual nsresult GetRoleInternal(PRUint32 *aRole); virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState); virtual nsresult GetARIAState(PRUint32 *aState, PRUint32 *aExtraState); - virtual void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry); - virtual nsIAccessible* GetParent(); // nsIAccessibleText NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor); diff --git a/accessible/src/base/nsOuterDocAccessible.cpp b/accessible/src/base/nsOuterDocAccessible.cpp index df962beffa7b..b42b062c03f0 100644 --- a/accessible/src/base/nsOuterDocAccessible.cpp +++ b/accessible/src/base/nsOuterDocAccessible.cpp @@ -99,11 +99,25 @@ nsOuterDocAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, return NS_OK; } -void -nsOuterDocAccessible::CacheChildren() -{ - // An outer doc accessible usually has 1 nsDocAccessible child, but could have - // none if we can't get to the inner documnet. +void nsOuterDocAccessible::CacheChildren() +{ + // An outer doc accessible usually has 1 nsDocAccessible child, + // but could have none if we can't get to the inner documnet + if (!mWeakShell) { + mAccChildCount = eChildCountUninitialized; + return; // This outer doc node has been shut down + } + if (mAccChildCount != eChildCountUninitialized) { + return; + } + + InvalidateChildren(); + mAccChildCount = 0; + + // In these variable names, "outer" relates to the nsOuterDocAccessible + // as opposed to the nsDocAccessibleWrap which is "inner". + // The outer node is a something like a , ,