mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 592913 - provide a way to quickly determine whether an accessible object is a descendant of a tab document, r=marcoz, davidb, a=blocking
This commit is contained in:
parent
c5cea9abde
commit
0ee231bcdf
@ -56,7 +56,7 @@ interface nsIDOMWindow;
|
||||
* nsIAccessNode::GetAccessibleDocument() or
|
||||
* nsIAccessibleEvent::GetAccessibleDocument()
|
||||
*/
|
||||
[scriptable, uuid(03c6ce8a-aa40-4484-9282-e6579c56e054)]
|
||||
[scriptable, uuid(451242bd-8a0c-4198-ae88-c053609a4e5d)]
|
||||
interface nsIAccessibleDocument : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -99,4 +99,19 @@ interface nsIAccessibleDocument : nsISupports
|
||||
* For example, in Windows you can static cast it to an HWND.
|
||||
*/
|
||||
[noscript] readonly attribute voidPtr windowHandle;
|
||||
|
||||
/**
|
||||
* Return the parent document accessible.
|
||||
*/
|
||||
readonly attribute nsIAccessibleDocument parentDocument;
|
||||
|
||||
/**
|
||||
* Return the count of child document accessibles.
|
||||
*/
|
||||
readonly attribute unsigned long childDocumentCount;
|
||||
|
||||
/**
|
||||
* Return the child document accessible at the given index.
|
||||
*/
|
||||
nsIAccessibleDocument getChildDocumentAt(in unsigned long index);
|
||||
};
|
||||
|
@ -133,11 +133,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEventQueue");
|
||||
cb.NoteXPCOMChild(tmp->mEventQueue.get());
|
||||
|
||||
PRUint32 i, length = tmp->mChildDocuments.Length();
|
||||
for (i = 0; i < length; ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildDocuments[i]");
|
||||
cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mChildDocuments[i].get()));
|
||||
}
|
||||
|
||||
CycleCollectorTraverseCache(tmp->mAccessibleCache, &cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventQueue)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mChildDocuments)
|
||||
ClearCache(tmp->mAccessibleCache);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
@ -498,6 +505,44 @@ nsDocAccessible::GetDOMDocument(nsIDOMDocument **aDOMDocument)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocAccessible::GetParentDocument(nsIAccessibleDocument** aDocument)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
*aDocument = nsnull;
|
||||
|
||||
if (!IsDefunct())
|
||||
NS_IF_ADDREF(*aDocument = ParentDocument());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocAccessible::GetChildDocumentCount(PRUint32* aCount)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCount);
|
||||
*aCount = 0;
|
||||
|
||||
if (!IsDefunct())
|
||||
*aCount = ChildDocumentCount();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocAccessible::GetChildDocumentAt(PRUint32 aIndex,
|
||||
nsIAccessibleDocument** aDocument)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
*aDocument = nsnull;
|
||||
|
||||
if (IsDefunct())
|
||||
return NS_OK;
|
||||
|
||||
NS_IF_ADDREF(*aDocument = GetChildDocumentAt(aIndex));
|
||||
return *aDocument ? NS_OK : NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// nsIAccessibleHyperText method
|
||||
NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor)
|
||||
{
|
||||
@ -531,6 +576,7 @@ NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsDocAccessible public method
|
||||
nsAccessible *
|
||||
nsDocAccessible::GetCachedAccessible(void *aUniqueID)
|
||||
{
|
||||
@ -603,6 +649,10 @@ nsDocAccessible::Init()
|
||||
|
||||
AddEventListeners();
|
||||
|
||||
nsDocAccessible* parentDocument = mParent->GetDocAccessible();
|
||||
if (parentDocument)
|
||||
parentDocument->AppendChildDocument(this);
|
||||
|
||||
// Fire reorder event to notify new accessible document has been created and
|
||||
// attached to the tree.
|
||||
nsRefPtr<AccEvent> reorderEvent =
|
||||
@ -629,8 +679,15 @@ nsDocAccessible::Shutdown()
|
||||
|
||||
RemoveEventListeners();
|
||||
|
||||
if (mParent)
|
||||
if (mParent) {
|
||||
nsDocAccessible* parentDocument = mParent->GetDocAccessible();
|
||||
if (parentDocument)
|
||||
parentDocument->RemoveChildDocument(this);
|
||||
|
||||
mParent->RemoveChild(this);
|
||||
}
|
||||
|
||||
mChildDocuments.Clear();
|
||||
|
||||
mWeakShell = nsnull; // Avoid reentrancy
|
||||
|
||||
@ -1278,6 +1335,23 @@ nsDocAccessible::HandleAccEvent(AccEvent* aAccEvent)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Public members
|
||||
|
||||
nsAccessible*
|
||||
nsDocAccessible::GetCachedAccessibleInSubtree(void* aUniqueID)
|
||||
{
|
||||
nsAccessible* child = GetCachedAccessible(aUniqueID);
|
||||
if (child)
|
||||
return child;
|
||||
|
||||
PRUint32 childDocCount = mChildDocuments.Length();
|
||||
for (PRUint32 childDocIdx= 0; childDocIdx < childDocCount; childDocIdx++) {
|
||||
nsDocAccessible* childDocument = mChildDocuments.ElementAt(childDocIdx);
|
||||
child = childDocument->GetCachedAccessibleInSubtree(aUniqueID);
|
||||
if (child)
|
||||
return child;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected members
|
||||
|
@ -141,6 +141,24 @@ public:
|
||||
*/
|
||||
void MarkAsLoaded() { mIsLoaded = PR_TRUE; }
|
||||
|
||||
/**
|
||||
* Return the parent document.
|
||||
*/
|
||||
nsDocAccessible* ParentDocument() const
|
||||
{ return mParent ? mParent->GetDocAccessible() : nsnull; }
|
||||
|
||||
/**
|
||||
* Return the child document count.
|
||||
*/
|
||||
PRUint32 ChildDocumentCount() const
|
||||
{ return mChildDocuments.Length(); }
|
||||
|
||||
/**
|
||||
* Return the child document at the given index.
|
||||
*/
|
||||
nsDocAccessible* GetChildDocumentAt(PRUint32 aIndex) const
|
||||
{ return mChildDocuments.SafeElementAt(aIndex, nsnull); }
|
||||
|
||||
/**
|
||||
* Non-virtual method to fire a delayed event after a 0 length timeout.
|
||||
*
|
||||
@ -188,6 +206,12 @@ public:
|
||||
*/
|
||||
nsAccessible* GetCachedAccessible(void *aUniqueID);
|
||||
|
||||
/**
|
||||
* Return the cached accessible by the given unique ID looking through
|
||||
* this and nested documents.
|
||||
*/
|
||||
nsAccessible* GetCachedAccessibleInSubtree(void* aUniqueID);
|
||||
|
||||
/**
|
||||
* Cache the accessible.
|
||||
*
|
||||
@ -217,6 +241,24 @@ protected:
|
||||
void AddScrollListener();
|
||||
void RemoveScrollListener();
|
||||
|
||||
/**
|
||||
* Append the given document accessible to this document's child document
|
||||
* accessibles.
|
||||
*/
|
||||
bool AppendChildDocument(nsDocAccessible* aChildDocument)
|
||||
{
|
||||
return mChildDocuments.AppendElement(aChildDocument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given document accessible from this document's child document
|
||||
* accessibles.
|
||||
*/
|
||||
void RemoveChildDocument(nsDocAccessible* aChildDocument)
|
||||
{
|
||||
mChildDocuments.RemoveElement(aChildDocument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate parent-child relations for any cached accessible in the DOM
|
||||
* subtree. Accessible objects aren't destroyed.
|
||||
@ -337,6 +379,8 @@ protected:
|
||||
|
||||
static PRUint32 gLastFocusedAccessiblesState;
|
||||
static nsIAtom *gLastFocusedFrameType;
|
||||
|
||||
nsTArray<nsRefPtr<nsDocAccessible> > mChildDocuments;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsDocAccessible,
|
||||
|
@ -282,24 +282,21 @@ STDMETHODIMP nsAccessibleWrap::get_accChild(
|
||||
{
|
||||
__try {
|
||||
*ppdispChild = NULL;
|
||||
if (!mWeakShell || varChild.vt != VT_I4)
|
||||
if (IsDefunct())
|
||||
return E_FAIL;
|
||||
|
||||
if (varChild.lVal == CHILDID_SELF) {
|
||||
*ppdispChild = static_cast<IDispatch*>(this);
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
// IAccessible::accChild is used to return this accessible or child accessible
|
||||
// at the given index or to get an accessible by child ID in the case of
|
||||
// document accessible (it's handled by overriden GetXPAccessibleFor method
|
||||
// on the document accessible). The getting an accessible by child ID is used
|
||||
// by AccessibleObjectFromEvent() called by AT when AT handles our MSAA event.
|
||||
nsAccessible* child = GetXPAccessibleFor(varChild);
|
||||
if (child)
|
||||
*ppdispChild = NativeAccessible(child);
|
||||
|
||||
if (!nsAccUtils::MustPrune(this)) {
|
||||
nsAccessible* child = GetChildAt(varChild.lVal - 1);
|
||||
if (child) {
|
||||
*ppdispChild = NativeAccessible(child);
|
||||
}
|
||||
}
|
||||
} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
|
||||
|
||||
return (*ppdispChild)? S_OK: E_FAIL;
|
||||
return (*ppdispChild)? S_OK: E_INVALIDARG;
|
||||
}
|
||||
|
||||
STDMETHODIMP nsAccessibleWrap::get_accName(
|
||||
@ -1804,7 +1801,7 @@ nsAccessibleWrap::UnattachIEnumVariant()
|
||||
nsAccessible*
|
||||
nsAccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
|
||||
{
|
||||
if (IsDefunct())
|
||||
if (aVarChild.vt != VT_I4)
|
||||
return nsnull;
|
||||
|
||||
// if its us real easy - this seems to always be the case
|
||||
|
@ -103,39 +103,13 @@ nsDocAccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
|
||||
// accessible through whole accessible subtree including subdocuments.
|
||||
// Otherwise we treat lVal as index in parent.
|
||||
|
||||
if (aVarChild.lVal < 0)
|
||||
return IsDefunct() ? nsnull : GetXPAccessibleForChildID(aVarChild);
|
||||
|
||||
return nsAccessibleWrap::GetXPAccessibleFor(aVarChild);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
nsDocAccessibleWrap::get_accChild(VARIANT varChild,
|
||||
IDispatch __RPC_FAR *__RPC_FAR *ppdispChild)
|
||||
{
|
||||
__try {
|
||||
*ppdispChild = NULL;
|
||||
|
||||
if (varChild.vt == VT_I4 && varChild.lVal < 0) {
|
||||
// IAccessible::accChild can be used to get an accessible by child ID.
|
||||
// It is used by AccessibleObjectFromEvent() called by AT when AT handles
|
||||
// our MSAA event.
|
||||
|
||||
nsAccessible *xpAccessible = GetXPAccessibleForChildID(varChild);
|
||||
if (!xpAccessible)
|
||||
return E_FAIL;
|
||||
|
||||
IAccessible *msaaAccessible = NULL;
|
||||
xpAccessible->GetNativeInterface((void**)&msaaAccessible);
|
||||
*ppdispChild = static_cast<IDispatch*>(msaaAccessible);
|
||||
|
||||
return S_OK;
|
||||
if (aVarChild.vt == VT_I4 && aVarChild.lVal < 0) {
|
||||
// Convert child ID to unique ID.
|
||||
void* uniqueID = reinterpret_cast<void*>(-aVarChild.lVal);
|
||||
return GetCachedAccessibleInSubtree(uniqueID);
|
||||
}
|
||||
|
||||
// Otherwise, the normal get_accChild() will do
|
||||
return nsAccessibleWrap::get_accChild(varChild, ppdispChild);
|
||||
} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
|
||||
return E_FAIL;
|
||||
return nsAccessibleWrap::GetXPAccessibleFor(aVarChild);
|
||||
}
|
||||
|
||||
STDMETHODIMP nsDocAccessibleWrap::get_URL(/* [out] */ BSTR __RPC_FAR *aURL)
|
||||
@ -271,14 +245,3 @@ STDMETHODIMP nsDocAccessibleWrap::get_accValue(
|
||||
|
||||
return get_URL(pszValue);
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
nsDocAccessibleWrap::GetXPAccessibleForChildID(const VARIANT& aVarChild)
|
||||
{
|
||||
NS_PRECONDITION(aVarChild.vt == VT_I4 && aVarChild.lVal < 0,
|
||||
"Variant doesn't point to child ID!");
|
||||
|
||||
// Convert child ID to unique ID.
|
||||
void *uniqueID = reinterpret_cast<void*>(-aVarChild.lVal);
|
||||
return GetAccService()->FindAccessibleInCache(uniqueID);
|
||||
}
|
||||
|
@ -83,10 +83,6 @@ public:
|
||||
/* [in] */ BSTR __RPC_FAR *commaSeparatedMediaTypes);
|
||||
|
||||
// IAccessible
|
||||
// Override get_accChild so that it can get any child via the unique ID
|
||||
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChild(
|
||||
/* [in] */ VARIANT varChild,
|
||||
/* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild);
|
||||
|
||||
// Override get_accValue to provide URL when no other value is available
|
||||
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue(
|
||||
@ -95,15 +91,6 @@ public:
|
||||
|
||||
// nsAccessibleWrap
|
||||
virtual nsAccessible *GetXPAccessibleFor(const VARIANT& varChild);
|
||||
|
||||
// nsDocAccessibleWrap
|
||||
|
||||
/**
|
||||
* Find an accessible by the given child ID in cached documents.
|
||||
*
|
||||
* @param aVarChild [in] variant pointing to the child ID
|
||||
*/
|
||||
static nsAccessible *GetXPAccessibleForChildID(const VARIANT& aVarChild);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -53,6 +53,7 @@ _TEST_FILES =\
|
||||
test_colorpicker.xul \
|
||||
test_combobox.xul \
|
||||
test_cssoverflow.html \
|
||||
test_dochierarchy.html \
|
||||
test_filectrl.html \
|
||||
test_formctrl.html \
|
||||
test_formctrl.xul \
|
||||
|
83
accessible/tests/mochitest/tree/test_dochierarchy.html
Normal file
83
accessible/tests/mochitest/tree/test_dochierarchy.html
Normal file
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test document hierarchy</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../states.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
{
|
||||
// tabDoc and testDoc are different documents depending on whether test
|
||||
// is running in standalone mode or not.
|
||||
|
||||
var root = getRootAccessible();
|
||||
var tabDoc = window.parent ?
|
||||
getAccessible(window.parent.document, [nsIAccessibleDocument]) :
|
||||
getAccessible(document, [nsIAccessibleDocument]);
|
||||
var testDoc = getAccessible(document, [nsIAccessibleDocument]);
|
||||
var iframeDoc = getAccessible("iframe").firstChild.
|
||||
QueryInterface(nsIAccessibleDocument);
|
||||
|
||||
is(root.parentDocument, null,
|
||||
"Wrong parent document of root accessible");
|
||||
is(root.childDocumentCount, 1,
|
||||
"Wrong child document count of root accessible");
|
||||
is(root.getChildDocumentAt(0), tabDoc,
|
||||
"Wrong child document at index 0 of root accessible");
|
||||
|
||||
is(tabDoc.parentDocument, root,
|
||||
"Wrong parent document of tab document");
|
||||
is(tabDoc.childDocumentCount, 1,
|
||||
"Wrong child document count of tab document");
|
||||
is(tabDoc.getChildDocumentAt(0), (tabDoc == testDoc ? iframeDoc : testDoc),
|
||||
"Wrong child document at index 0 of tab document");
|
||||
|
||||
if (tabDoc != testDoc) {
|
||||
is(testDoc.parentDocument, tabDoc,
|
||||
"Wrong parent document of test document");
|
||||
is(testDoc.childDocumentCount, 1,
|
||||
"Wrong child document count of test document");
|
||||
is(testDoc.getChildDocumentAt(0), iframeDoc,
|
||||
"Wrong child document at index 0 of test document");
|
||||
}
|
||||
|
||||
is(iframeDoc.parentDocument, (tabDoc == testDoc ? tabDoc : testDoc),
|
||||
"Wrong parent document of iframe document");
|
||||
is(iframeDoc.childDocumentCount, 0,
|
||||
"Wrong child document count of iframe document");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=592913"
|
||||
title="Provide a way to quickly determine whether an accessible object is a descendant of a tab document">
|
||||
Mozilla Bug 592913
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<iframe src="about:mozilla" id="iframe"></iframe>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user