bug 108791 - infinite recursion crash when tabbing if there is no focusable content. r=saari, sr=sfraser.

This commit is contained in:
bryner%netscape.com 2002-02-01 05:14:44 +00:00
Родитель 6f66239aa4
Коммит 1ebc6d2820
2 изменённых файлов: 35 добавлений и 13 удалений

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

@ -2553,11 +2553,24 @@ PrintDocTree(nsIDocShellTreeNode * aParentNode, int aLevel)
#endif // end debug helpers #endif // end debug helpers
NS_IMETHODIMP NS_IMETHODIMP
nsEventStateManager::ShiftFocus(PRBool forward, nsIContent* aStart) nsEventStateManager::ShiftFocus(PRBool aForward, nsIContent* aStart)
{
// We use mTabbedThroughDocument to indicate that we have passed
// the end (or beginning) of the document we started tabbing from,
// without finding anything else to focus. If we pass the end of
// the same document again (and the flag is set), we know that there
// is no focusable content anywhere in the tree, and should stop.
mTabbedThroughDocument = PR_FALSE;
return ShiftFocusInternal(aForward, aStart);
}
nsresult
nsEventStateManager::ShiftFocusInternal(PRBool aForward, nsIContent* aStart)
{ {
#ifdef DEBUG_DOCSHELL_FOCUS #ifdef DEBUG_DOCSHELL_FOCUS
printf("[%p] ShiftFocus: forward=%d, aStart=%p, mCurrentFocus=%p\n", printf("[%p] ShiftFocus: aForward=%d, aStart=%p, mCurrentFocus=%p\n",
this, forward, aStart, mCurrentFocus); this, aForward, aStart, mCurrentFocus);
#endif #endif
NS_ASSERTION(mPresContext, "no pres context"); NS_ASSERTION(mPresContext, "no pres context");
EnsureDocument(mPresContext); EnsureDocument(mPresContext);
@ -2600,7 +2613,7 @@ nsEventStateManager::ShiftFocus(PRBool forward, nsIContent* aStart)
// So, use the docshell focus state to disambiguate. // So, use the docshell focus state to disambiguate.
docShell->GetHasFocus(&docHasFocus); docShell->GetHasFocus(&docHasFocus);
if (forward) { if (aForward) {
mCurrentFocus = rootContent; mCurrentFocus = rootContent;
NS_IF_ADDREF(mCurrentFocus); NS_IF_ADDREF(mCurrentFocus);
mCurrentTabIndex = 1; mCurrentTabIndex = 1;
@ -2627,8 +2640,8 @@ nsEventStateManager::ShiftFocus(PRBool forward, nsIContent* aStart)
presShell->GetPrimaryFrameFor(mCurrentFocus, &curFocusFrame); presShell->GetPrimaryFrameFor(mCurrentFocus, &curFocusFrame);
nsCOMPtr<nsIContent> nextFocus; nsCOMPtr<nsIContent> nextFocus;
if (forward || !docHasFocus) if (aForward || !docHasFocus)
GetNextTabbableContent(rootContent, curFocusFrame, forward, GetNextTabbableContent(rootContent, curFocusFrame, aForward,
getter_AddRefs(nextFocus)); getter_AddRefs(nextFocus));
if (nextFocus) { if (nextFocus) {
@ -2648,7 +2661,7 @@ nsEventStateManager::ShiftFocus(PRBool forward, nsIContent* aStart)
presShell->GetPrimaryFrameFor(nextFocus, &nextFocusFrame); presShell->GetPrimaryFrameFor(nextFocus, &nextFocusFrame);
presShell->ScrollFrameIntoView(nextFocusFrame, NS_PRESSHELL_SCROLL_ANYWHERE, presShell->ScrollFrameIntoView(nextFocusFrame, NS_PRESSHELL_SCROLL_ANYWHERE,
NS_PRESSHELL_SCROLL_ANYWHERE); NS_PRESSHELL_SCROLL_ANYWHERE);
TabIntoDocument(subShell, forward); TabIntoDocument(subShell, aForward);
} }
} else { } else {
// there is no subshell, so just focus nextFocus // there is no subshell, so just focus nextFocus
@ -2683,7 +2696,7 @@ nsEventStateManager::ShiftFocus(PRBool forward, nsIContent* aStart)
focusDocument = !(IsFrameSetDoc(docShell)); focusDocument = !(IsFrameSetDoc(docShell));
} }
if (!forward && !docHasFocus && focusDocument) { if (!aForward && !docHasFocus && focusDocument) {
#ifdef DEBUG_DOCSHELL_FOCUS #ifdef DEBUG_DOCSHELL_FOCUS
printf("Focusing document\n"); printf("Focusing document\n");
#endif #endif
@ -2696,6 +2709,11 @@ nsEventStateManager::ShiftFocus(PRBool forward, nsIContent* aStart)
// in the same direction starting at the content element // in the same direction starting at the content element
// corresponding to our docshell. // corresponding to our docshell.
// Guard against infinite recursion (see explanation in ShiftFocus)
if (mTabbedThroughDocument)
return NS_OK;
mTabbedThroughDocument = PR_TRUE;
nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(pcContainer); nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(pcContainer);
nsCOMPtr<nsIDocShellTreeItem> treeParent; nsCOMPtr<nsIDocShellTreeItem> treeParent;
treeItem->GetParent(getter_AddRefs(treeParent)); treeItem->GetParent(getter_AddRefs(treeParent));
@ -2720,13 +2738,13 @@ nsEventStateManager::ShiftFocus(PRBool forward, nsIContent* aStart)
printf("popping out focus to parent docshell\n"); printf("popping out focus to parent docshell\n");
#endif #endif
parentESM->ShiftFocus(forward, shellContent); parentESM->ShiftFocus(aForward, shellContent);
} }
} else { } else {
PRBool tookFocus = PR_FALSE; PRBool tookFocus = PR_FALSE;
nsCOMPtr<nsIDocShell> subShell = do_QueryInterface(pcContainer); nsCOMPtr<nsIDocShell> subShell = do_QueryInterface(pcContainer);
if (subShell) if (subShell)
subShell->TabToTreeOwner(forward, &tookFocus); subShell->TabToTreeOwner(aForward, &tookFocus);
#ifdef DEBUG_DOCSHEL_FOCUS #ifdef DEBUG_DOCSHEL_FOCUS
printf("offered focus to tree owner, tookFocus=%d\n", printf("offered focus to tree owner, tookFocus=%d\n",
@ -2746,7 +2764,7 @@ nsEventStateManager::ShiftFocus(PRBool forward, nsIContent* aStart)
NS_IF_RELEASE(mCurrentFocus); NS_IF_RELEASE(mCurrentFocus);
docShell->SetHasFocus(PR_FALSE); docShell->SetHasFocus(PR_FALSE);
ShiftFocus(forward); ShiftFocusInternal(aForward);
} }
} }
} }

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

@ -130,7 +130,7 @@ public:
//Method for centralized distribution of new DOM events //Method for centralized distribution of new DOM events
NS_IMETHOD DispatchNewEvent(nsISupports* aTarget, nsIDOMEvent* aEvent, PRBool *aPreventDefault); NS_IMETHOD DispatchNewEvent(nsISupports* aTarget, nsIDOMEvent* aEvent, PRBool *aPreventDefault);
NS_IMETHOD ShiftFocus(PRBool forward, nsIContent* aStart=nsnull); NS_IMETHOD ShiftFocus(PRBool aForward, nsIContent* aStart=nsnull);
protected: protected:
void UpdateCursor(nsIPresContext* aPresContext, nsEvent* aEvent, nsIFrame* aTargetFrame, nsEventStatus* aStatus); void UpdateCursor(nsIPresContext* aPresContext, nsEvent* aEvent, nsIFrame* aTargetFrame, nsEventStatus* aStatus);
@ -152,6 +152,7 @@ protected:
// DocShell Focus Traversal Methods // DocShell Focus Traversal Methods
//--------------------------------------------- //---------------------------------------------
nsresult ShiftFocusInternal(PRBool aForward, nsIContent* aStart = nsnull);
void TabIntoDocument(nsIDocShell* aDocShell, PRBool aForward); void TabIntoDocument(nsIDocShell* aDocShell, PRBool aForward);
void ShiftFocusByDoc(PRBool forward); void ShiftFocusByDoc(PRBool forward);
PRBool IsFrameSetDoc(nsIDocShell* aDocShell); PRBool IsFrameSetDoc(nsIDocShell* aDocShell);
@ -254,6 +255,9 @@ protected:
// So we don't have to keep checking accessibility.browsewithcaret pref // So we don't have to keep checking accessibility.browsewithcaret pref
PRBool mBrowseWithCaret; PRBool mBrowseWithCaret;
// Recursion guard for tabbing
PRBool mTabbedThroughDocument;
#ifdef CLICK_HOLD_CONTEXT_MENUS #ifdef CLICK_HOLD_CONTEXT_MENUS
enum { kClickHoldDelay = 500 } ; // 500ms == 1/2 second enum { kClickHoldDelay = 500 } ; // 500ms == 1/2 second