bug 417249, bug 417578, bug 405951, bug 413778, bug 412878. Fix missing, incorrect or crashing doc load events in Firefox and Thunderbird. r=surkov, a=blocking1.9

This commit is contained in:
aaronleventhal@moonset.net 2008-02-26 00:51:10 -08:00
Родитель 4bcebb89c2
Коммит a48279000e
11 изменённых файлов: 168 добавлений и 171 удалений

Просмотреть файл

@ -44,8 +44,9 @@ interface nsIDocument;
interface nsIFrame;
interface nsObjectFrame;
interface nsIContent;
interface nsITimer;
[uuid(933f7472-cbe3-4d95-a77a-ce7ea3812b32)]
[uuid(27386cf1-f27e-4d2d-9bf4-c4621d50d299)]
interface nsIAccessibilityService : nsIAccessibleRetrieval
{
nsIAccessible createOuterDocAccessible(in nsIDOMNode aNode);
@ -100,6 +101,17 @@ interface nsIAccessibilityService : nsIAccessibleRetrieval
void invalidateSubtreeFor(in nsIPresShell aPresShell,
in nsIContent aChangedContent,
in PRUint32 aEvent);
/**
* An internal doc load event has occured. Handle the event and remove it from the list.
* @param aTimer The timer created to handle this doc load event
* @param aClosure The nsIWebProgress* for the load event
* @param aEventType The type of load event, one of: nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START,
* nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE or
* nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED
*/
void processDocLoadEvent(in nsITimer aTimer, in voidPtr aClosure, in PRUint32 aEventType);
};

Просмотреть файл

@ -95,6 +95,9 @@ nsApplicationAccessibleWrap *nsAccessNode::gApplicationAccessible = nsnull;
nsIAccessibilityService *nsAccessNode::sAccService = nsnull;
nsIAccessibilityService *nsAccessNode::GetAccService()
{
if (!gIsAccessibilityActive)
return nsnull;
if (!sAccService) {
nsresult rv = CallGetService("@mozilla.org/accessibilityService;1",
&sAccService);
@ -315,7 +318,7 @@ void nsAccessNode::ShutdownXPAccessibility()
NS_IF_RELEASE(sAccService);
nsApplicationAccessibleWrap::Unload();
ClearCache(gGlobalDocAccessibleCache);
gGlobalDocAccessibleCache.Enumerate(ClearDocCacheEntry, nsnull);
// Release gApplicationAccessible after everything else is shutdown
// so we don't accidently create it again while tearing down root accessibles
@ -791,6 +794,14 @@ PLDHashOperator nsAccessNode::ClearCacheEntry(const void* aKey, nsCOMPtr<nsIAcce
return PL_DHASH_REMOVE;
}
PLDHashOperator nsAccessNode::ClearDocCacheEntry(const void* aKey, nsCOMPtr<nsIAccessNode>& aAccessNode, void* aUserArg)
{
nsCOMPtr<nsPIAccessNode> privateAccessNode(do_QueryInterface(aAccessNode));
privateAccessNode->Shutdown();
return PL_DHASH_NEXT; // nsDocAccessible::Shutdown() removes the doc from doc cache
}
void
nsAccessNode::ClearCache(nsAccessNodeHashtable& aCache)
{

Просмотреть файл

@ -98,6 +98,7 @@ class nsAccessNode: public nsIAccessNode, public nsPIAccessNode
static void ClearCache(nsAccessNodeHashtable& aCache);
static PLDHashOperator PR_CALLBACK ClearCacheEntry(const void* aKey, nsCOMPtr<nsIAccessNode>& aAccessNode, void* aUserArg);
static PLDHashOperator PR_CALLBACK ClearDocCacheEntry(const void* aKey, nsCOMPtr<nsIAccessNode>& aAccessNode, void* aUserArg);
// Static cache methods for global document cache
static already_AddRefed<nsIAccessibleDocument> GetDocAccessibleFor(nsIDocument *aDocument);

Просмотреть файл

@ -41,6 +41,7 @@
#include "nsAccessibilityService.h"
#include "nsAccessibilityUtils.h"
#include "nsARIAMap.h"
#include "nsIContentViewer.h"
#include "nsCURILoader.h"
#include "nsDocAccessible.h"
#include "nsHTMLImageAccessibleWrap.h"
@ -155,10 +156,21 @@ nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic,
observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
}
nsCOMPtr<nsIWebProgress> progress(do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID));
if (progress) {
if (progress)
progress->RemoveProgressListener(static_cast<nsIWebProgressListener*>(this));
}
nsAccessNodeWrap::ShutdownAccessibility();
// Cancel and release load timers
while (mLoadTimers.Count() > 0 ) {
nsCOMPtr<nsITimer> timer = mLoadTimers.ObjectAt(0);
void *closure = nsnull;
timer->GetClosure(&closure);
if (closure) {
nsIWebProgress *webProgress = static_cast<nsIWebProgress*>(closure);
NS_RELEASE(webProgress); // Release nsIWebProgress for timer
}
timer->Cancel();
mLoadTimers.RemoveObjectAt(0);
}
}
return NS_OK;
}
@ -169,70 +181,94 @@ NS_IMETHODIMP nsAccessibilityService::OnStateChange(nsIWebProgress *aWebProgress
{
NS_ASSERTION(aStateFlags & STATE_IS_DOCUMENT, "Other notifications excluded");
if (0 == (aStateFlags & (STATE_START | STATE_STOP))) {
if (!aWebProgress || 0 == (aStateFlags & (STATE_START | STATE_STOP))) {
return NS_OK;
}
nsCAutoString name;
aRequest->GetName(name);
if (name.EqualsLiteral("about:blank"))
return NS_OK;
if (NS_FAILED(aStatus) && (aStateFlags & STATE_START))
return NS_OK;
nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
if (!timer)
return NS_OK;
mLoadTimers.AppendObject(timer);
NS_ADDREF(aWebProgress);
if (aStateFlags & STATE_START)
timer->InitWithFuncCallback(StartLoadCallback, aWebProgress, 0,
nsITimer::TYPE_ONE_SHOT);
else if (NS_SUCCEEDED(aStatus))
timer->InitWithFuncCallback(EndLoadCallback, aWebProgress, 0,
nsITimer::TYPE_ONE_SHOT);
else // Failed end load
timer->InitWithFuncCallback(FailedLoadCallback, aWebProgress, 0,
nsITimer::TYPE_ONE_SHOT);
return NS_OK;
}
NS_IMETHODIMP nsAccessibilityService::ProcessDocLoadEvent(nsITimer *aTimer, void *aClosure, PRUint32 aEventType)
{
nsCOMPtr<nsIDOMWindow> domWindow;
aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
NS_ASSERTION(domWindow, "DOM Window for state change is null");
NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
nsIWebProgress *webProgress = static_cast<nsIWebProgress*>(aClosure);
webProgress->GetDOMWindow(getter_AddRefs(domWindow));
NS_RELEASE(webProgress);
mLoadTimers.RemoveObject(aTimer);
NS_ENSURE_STATE(domWindow);
nsCOMPtr<nsIDOMDocument> domDoc;
domWindow->GetDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDOMNode> domDocNode(do_QueryInterface(domDoc));
NS_ENSURE_TRUE(domDocNode, NS_ERROR_FAILURE);
nsCOMPtr<nsIAccessibleDocument> docAccessible;
PRUint32 eventType = 0;
if (aStateFlags & STATE_STOP) {
// Do not create accessible for page load end events
// in case it was already shut down before page finished loading
docAccessible = nsAccessNode::GetDocAccessibleFor(domDocNode); // Cached doc accessibles only
if (!docAccessible)
return NS_OK;
nsCOMPtr<nsIDOMDocument> domDocTest;
docAccessible->GetDocument(getter_AddRefs(domDocTest));
if (domDocTest != domDoc) {
// Doc from accessible is not the doc we started from
// We must be shutdown, and domDocTest should be null
NS_ASSERTION(!domDocTest, "Doc not shut down but reports incorrect DOM document");
return NS_OK;
}
eventType = NS_FAILED(aStatus) ? nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED :
nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE;
}
else {
// Get the accessible for the new document.
// If it not created yet this will create it & cache it, as well as
// set up event listeners so that MSAA/ATK toolkit and internal
// accessibility events will get fired.
nsCOMPtr<nsIAccessible> accessible;
GetAccessibleFor(domDocNode, getter_AddRefs(accessible)); // Create if necessary
docAccessible = do_QueryInterface(accessible);
eventType = nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START;
if (aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START) {
nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(domWindow));
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav));
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
NS_ENSURE_STATE(docShell);
PRUint32 loadType;
docShell->GetLoadType(&loadType);
if (loadType == LOAD_RELOAD_NORMAL ||
loadType == LOAD_RELOAD_BYPASS_CACHE ||
loadType == LOAD_RELOAD_BYPASS_PROXY ||
loadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE) {
eventType = nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD;
aEventType = nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD;
}
}
nsCOMPtr<nsPIAccessibleDocument> privDocAccessible = do_QueryInterface(docAccessible);
if (eventType && privDocAccessible) {
privDocAccessible->FireDocLoadEvents(eventType);
}
nsCOMPtr<nsIDOMDocument> domDoc;
domWindow->GetDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDOMNode> docNode = do_QueryInterface(domDoc);
NS_ENSURE_STATE(docNode);
nsCOMPtr<nsIAccessible> accessible;
GetAccessibleFor(docNode, getter_AddRefs(accessible));
nsCOMPtr<nsPIAccessibleDocument> privDocAccessible = do_QueryInterface(accessible);
NS_ENSURE_STATE(privDocAccessible);
privDocAccessible->FireDocLoadEvents(aEventType);
return NS_OK;
}
void nsAccessibilityService::StartLoadCallback(nsITimer *aTimer, void *aClosure)
{
nsIAccessibilityService *accService = nsAccessNode::GetAccService();
if (accService)
accService->ProcessDocLoadEvent(aTimer, aClosure, nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START);
}
void nsAccessibilityService::EndLoadCallback(nsITimer *aTimer, void *aClosure)
{
nsIAccessibilityService *accService = nsAccessNode::GetAccService();
if (accService)
accService->ProcessDocLoadEvent(aTimer, aClosure, nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE);
}
void nsAccessibilityService::FailedLoadCallback(nsITimer *aTimer, void *aClosure)
{
nsIAccessibilityService *accService = nsAccessNode::GetAccService();
if (accService)
accService->ProcessDocLoadEvent(aTimer, aClosure, nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED);
}
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP nsAccessibilityService::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress,
@ -378,6 +414,12 @@ nsAccessibilityService::CreateRootAccessible(nsIPresShell *aShell,
nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
nsCOMPtr<nsISupports> container = aDocument->GetContainer();
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
nsCOMPtr<nsIContentViewer> contentViewer;
docShell->GetContentViewer(getter_AddRefs(contentViewer));
NS_ENSURE_TRUE(contentViewer, NS_ERROR_FAILURE); // Doc was already shut down
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
do_QueryInterface(container);
NS_ENSURE_TRUE(docShellTreeItem, NS_ERROR_FAILURE);

Просмотреть файл

@ -40,7 +40,10 @@
#define __nsAccessibilityService_h__
#include "nsIAccessibilityService.h"
#include "nsCOMArray.h"
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
#include "nsWeakReference.h"
@ -135,6 +138,11 @@ private:
* @return PR_TRUE if there is a universal ARIA property set on the node
*/
PRBool HasUniversalAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell);
static void StartLoadCallback(nsITimer *aTimer, void *aClosure);
static void EndLoadCallback(nsITimer *aTimer, void *aClosure);
static void FailedLoadCallback(nsITimer *aTimer, void *aClosure);
nsCOMArray<nsITimer> mLoadTimers;
};
/**

Просмотреть файл

@ -78,11 +78,14 @@ void nsCaretAccessible::Shutdown()
nsresult nsCaretAccessible::ClearControlSelectionListener()
{
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryReferent(mCurrentControlSelection));
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
mCurrentControlSelection = nsnull;
mCurrentControl = nsnull;
mCurrentControlSelection = nsnull;
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryReferent(mCurrentControlSelection));
if (!selPrivate) {
return NS_OK;
}
return selPrivate->RemoveSelectionListener(this);
}

Просмотреть файл

@ -526,17 +526,13 @@ NS_IMETHODIMP nsDocAccessible::Shutdown()
nsAccUtils::GetDocShellTreeItemFor(mDOMNode);
ShutdownChildDocuments(treeItem);
if (mDocLoadTimer) {
mDocLoadTimer->Cancel();
mDocLoadTimer = nsnull;
}
RemoveEventListeners();
mWeakShell = nsnull; // Avoid reentrancy
ClearCache(mAccessNodeCache);
nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument;
mDocument = nsnull;
nsHyperTextAccessibleWrap::Shutdown();
@ -553,6 +549,10 @@ NS_IMETHODIMP nsDocAccessible::Shutdown()
}
}
// Remove from the cache after other parts of Shutdown(), so that Shutdown() procedures
// can find the doc or root accessible in the cache if they need it.
gGlobalDocAccessibleCache.Remove(static_cast<void*>(kungFuDeathGripDoc));
return NS_OK;
}
@ -771,6 +771,14 @@ NS_IMETHODIMP nsDocAccessible::FireDocLoadEvents(PRUint32 aEventType)
}
mIsContentLoaded = isFinished;
nsCOMPtr<nsIDocShellTreeItem> treeItem =
nsAccUtils::GetDocShellTreeItemFor(mDOMNode);
if (!treeItem) {
return NS_OK;
}
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
if (isFinished) {
// Need to wait until scrollable view is available
AddScrollListener();
@ -780,36 +788,31 @@ NS_IMETHODIMP nsDocAccessible::FireDocLoadEvents(PRUint32 aEventType)
// Make the parent forget about the old document as a child
privateAccessible->InvalidateChildren();
}
// Use short timer before firing state change event for finished doc,
// because the window is made visible asynchronously
if (!mDocLoadTimer) {
mDocLoadTimer = do_CreateInstance("@mozilla.org/timer;1");
}
if (mDocLoadTimer) {
mDocLoadTimer->InitWithFuncCallback(DocLoadCallback, this, 0,
nsITimer::TYPE_ONE_SHOT);
}
} else {
nsCOMPtr<nsIDocShellTreeItem> treeItem =
nsAccUtils::GetDocShellTreeItemFor(mDOMNode);
if (!treeItem) {
return NS_OK;
}
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
if (sameTypeRoot != treeItem) {
return NS_OK;
// Fire show/hide events to indicate frame/iframe content is new, rather than
// doc load event which causes screen readers to act is if entire page is reloaded
InvalidateCacheSubtree(nsnull, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
}
// Loading document: fire EVENT_STATE_CHANGE to set STATE_BUSY
nsCOMPtr<nsIAccessibleStateChangeEvent> accEvent =
new nsAccStateChangeEvent(this, nsIAccessibleStates::STATE_BUSY,
PR_FALSE, PR_TRUE);
FireAccessibleEvent(accEvent);
}
nsAccUtils::FireAccEvent(aEventType, this);
// Fire STATE_CHANGE event for doc load finish if focus is in same doc tree
if (gLastFocusedNode) {
nsCOMPtr<nsIDocShellTreeItem> focusedTreeItem =
nsAccUtils::GetDocShellTreeItemFor(gLastFocusedNode);
if (focusedTreeItem) {
nsCOMPtr<nsIDocShellTreeItem> sameTypeRootOfFocus;
focusedTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRootOfFocus));
if (sameTypeRoot == sameTypeRootOfFocus) {
nsCOMPtr<nsIAccessibleStateChangeEvent> accEvent =
new nsAccStateChangeEvent(this, nsIAccessibleStates::STATE_BUSY, PR_FALSE, PR_FALSE);
FireAccessibleEvent(accEvent);
FireAnchorJumpEvent();
}
}
}
if (sameTypeRoot == treeItem) {
// Not a frame or iframe
nsAccUtils::FireAccEvent(aEventType, this);
}
return NS_OK;
}
@ -2067,55 +2070,3 @@ nsDocAccessible::FireShowHideEvents(nsIDOMNode *aDOMNode, PRBool aAvoidOnThisNod
return NS_OK;
}
void nsDocAccessible::DocLoadCallback(nsITimer *aTimer, void *aClosure)
{
// Doc has finished loading, fire "load finished" event
// By using short timer we can wait make the window visible,
// which it does asynchronously. This avoids confusing the screen reader with a
// hidden window. Waiting also allows us to see of the document has focus,
// which is important because we only fire doc loaded events for focused documents.
nsDocAccessible *docAcc =
reinterpret_cast<nsDocAccessible*>(aClosure);
if (!docAcc) {
return;
}
// Fire doc finished event
nsCOMPtr<nsIDOMNode> docDomNode;
docAcc->GetDOMNode(getter_AddRefs(docDomNode));
nsCOMPtr<nsIDocument> doc(do_QueryInterface(docDomNode));
if (doc) {
nsCOMPtr<nsISupports> container = doc->GetContainer();
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(container);
if (!docShellTreeItem) {
return;
}
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
if (sameTypeRoot != docShellTreeItem) {
// A frame or iframe has finished loading new content
docAcc->InvalidateCacheSubtree(nsnull, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
return;
}
// Fire STATE_CHANGE event for doc load finish if focus is in same doc tree
if (gLastFocusedNode) {
nsCOMPtr<nsIDocShellTreeItem> focusedTreeItem =
nsAccUtils::GetDocShellTreeItemFor(gLastFocusedNode);
if (focusedTreeItem) {
nsCOMPtr<nsIDocShellTreeItem> sameTypeRootOfFocus;
focusedTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRootOfFocus));
if (sameTypeRoot == sameTypeRootOfFocus) {
nsCOMPtr<nsIAccessibleStateChangeEvent> accEvent =
new nsAccStateChangeEvent(docAcc, nsIAccessibleStates::STATE_BUSY,
PR_FALSE, PR_FALSE);
docAcc->FireAccessibleEvent(accEvent);
docAcc->FireAnchorJumpEvent();
}
}
}
}
}

Просмотреть файл

@ -221,10 +221,6 @@ protected:
PRBool mIsAnchorJumped;
static PRUint32 gLastFocusedAccessiblesState;
static nsIAtom *gLastFocusedFrameType;
private:
static void DocLoadCallback(nsITimer *aTimer, void *aClosure);
nsCOMPtr<nsITimer> mDocLoadTimer;
};
#endif

Просмотреть файл

@ -406,29 +406,11 @@ void nsRootAccessible::TryFireEarlyLoadEvent(nsIDOMNode *aDocNode)
nsCOMPtr<nsIDocShellTreeItem> rootContentTreeItem;
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(rootContentTreeItem));
NS_ASSERTION(rootContentTreeItem, "No root content tree item");
if (!rootContentTreeItem) { // Not at root of content
return;
if (rootContentTreeItem == treeItem) {
// No frames or iframes, so we can fire the doc load finished event early
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD, aDocNode,
eRemoveDupes);
}
if (rootContentTreeItem != treeItem) {
nsCOMPtr<nsIAccessibleDocument> rootContentDocAccessible =
GetDocAccessibleFor(rootContentTreeItem);
nsCOMPtr<nsIAccessible> rootContentAccessible =
do_QueryInterface(rootContentDocAccessible);
if (!rootContentAccessible) {
return;
}
PRUint32 state, extState;
rootContentAccessible->GetFinalState(&state, &extState);
if ((state & nsIAccessibleStates::STATE_BUSY) ||
(extState & nsIAccessibleStates::EXT_STATE_DEFUNCT)) {
// Don't fire page load events on subdocuments for initial page load of entire page
return;
}
}
// No frames or iframes, so we can fire the doc load finished event early
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD, aDocNode,
eRemoveDupes);
}
PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
@ -632,9 +614,6 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
nsCOMPtr<nsPIAccessNode> privateAcc = do_QueryInterface(accDoc);
if (privateAcc) {
privateAcc->Shutdown();
// Remove from the cache after Shutdown(), so that Shutdown() procedures
// can find the doc or root accessible in the cache if they need it.
gGlobalDocAccessibleCache.Remove(static_cast<void*>(doc));
}
return NS_OK;
}

Просмотреть файл

@ -162,11 +162,6 @@ __try {
return E_FAIL;
}
NS_IMETHODIMP nsDocAccessibleWrap::Shutdown()
{
return nsDocAccessible::Shutdown();
}
NS_IMETHODIMP nsDocAccessibleWrap::FireAnchorJumpEvent()
{
// Staying on the same page, jumping to a named anchor

Просмотреть файл

@ -87,7 +87,6 @@ public:
/* [in] */ VARIANT varChild,
/* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild);
NS_IMETHOD Shutdown();
NS_IMETHOD FireAnchorJumpEvent();
};