diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index d250d79d5ca..fdafa68ec69 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -726,6 +726,8 @@ nsDocument::Reset(nsIURL *aURL) } if (nsnull != mRootContent) { + // Ensure that document is nsnull to allow validity checks on content + mRootContent->SetDocument(nsnull, PR_TRUE); ContentRemoved(nsnull, mRootContent, 0); NS_IF_RELEASE(mRootContent); } diff --git a/mozilla/content/base/src/nsGenericElement.cpp b/mozilla/content/base/src/nsGenericElement.cpp index f4f837cdef8..5580161c961 100644 --- a/mozilla/content/base/src/nsGenericElement.cpp +++ b/mozilla/content/base/src/nsGenericElement.cpp @@ -749,7 +749,7 @@ nsGenericElement::HandleDOMEvent(nsIPresContext& aPresContext, } //Bubbling stage - if ((DOM_EVENT_CAPTURE != aFlags) && (mParent != nsnull)) { + if ((DOM_EVENT_CAPTURE != aFlags) && (mParent != nsnull) && (mDocument != nsnull)) { ret = mParent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, DOM_EVENT_BUBBLE, aEventStatus); } diff --git a/mozilla/content/events/public/nsIEventStateManager.h b/mozilla/content/events/public/nsIEventStateManager.h index e6cec3dfbd0..9d529c4db75 100644 --- a/mozilla/content/events/public/nsIEventStateManager.h +++ b/mozilla/content/events/public/nsIEventStateManager.h @@ -64,6 +64,8 @@ public: NS_IMETHOD GetLinkState(nsIContent *aLink, nsLinkEventState& aState) = 0; NS_IMETHOD SetActiveLink(nsIContent *aLink) = 0; NS_IMETHOD SetHoverLink(nsIContent *aLink) = 0; + + NS_IMETHOD SetFocusedContent(nsIContent *aContent) = 0; }; #endif // nsIEventStateManager_h__ diff --git a/mozilla/content/events/src/Makefile.in b/mozilla/content/events/src/Makefile.in index 2daf92c43f8..f67b06aa5fd 100644 --- a/mozilla/content/events/src/Makefile.in +++ b/mozilla/content/events/src/Makefile.in @@ -44,7 +44,7 @@ EXPORTS = \ EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) -REQUIRES = xpcom raptor dom js +REQUIRES = xpcom raptor dom js netlib include $(topsrcdir)/config/config.mk diff --git a/mozilla/content/events/src/makefile.win b/mozilla/content/events/src/makefile.win index 368f09ea6b4..2d30f4c3eb6 100644 --- a/mozilla/content/events/src/makefile.win +++ b/mozilla/content/events/src/makefile.win @@ -42,7 +42,7 @@ CPP_OBJS= .\$(OBJDIR)\nsEventListenerManager.obj \ EXPORTS= nsEventListenerManager.h nsEventStateManager.h nsDOMEvent.h nsDOMEventsIIDs.h LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor \ - -I$(PUBLIC)\dom -I$(PUBLIC)\js -I..\..\html\base\src + -I$(PUBLIC)\dom -I$(PUBLIC)\js -I..\..\html\base\src -I$(PUBLIC)\netlib LCFLAGS = \ $(LCFLAGS) \ diff --git a/mozilla/content/events/src/nsEventStateManager.cpp b/mozilla/content/events/src/nsEventStateManager.cpp index ebf2233dbbb..f9ba669cc50 100644 --- a/mozilla/content/events/src/nsEventStateManager.cpp +++ b/mozilla/content/events/src/nsEventStateManager.cpp @@ -31,6 +31,12 @@ #include "nsIDOMHTMLInputElement.h" #include "nsIDOMHTMLSelectElement.h" #include "nsIDOMHTMLTextAreaElement.h" +#include "nsIDOMHTMLAreaElement.h" +#include "nsIDOMHTMLButtonElement.h" +#include "nsIDOMHTMLObjectElement.h" +#include "nsINameSpaceManager.h" // for kNameSpaceID_HTML +#include "nsIWebShell.h" +#include "nsIFocusableContent.h" static NS_DEFINE_IID(kIEventStateManagerIID, NS_IEVENTSTATEMANAGER_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); @@ -38,6 +44,11 @@ static NS_DEFINE_IID(kIDOMHTMLAnchorElementIID, NS_IDOMHTMLANCHORELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLInputElementIID, NS_IDOMHTMLINPUTELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLTextAreaElementIID, NS_IDOMHTMLTEXTAREAELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLAreaElementIID, NS_IDOMHTMLAREAELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLObjectElementIID, NS_IDOMHTMLOBJECTELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLButtonElementIID, NS_IDOMHTMLBUTTONELEMENT_IID); +static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); nsEventStateManager::nsEventStateManager() { mLastMouseOverFrame = nsnull; @@ -51,6 +62,7 @@ nsEventStateManager::nsEventStateManager() { mCurrentFocus = nsnull; mDocument = nsnull; mPresContext = nsnull; + mCurrentTabIndex = 0; NS_INIT_REFCNT(); } @@ -89,10 +101,7 @@ nsEventStateManager::PreHandleEvent(nsIPresContext& aPresContext, //GenerateMouseEnterExit(aPresContext, aEvent, aTargetFrame); break; case NS_GOTFOCUS: - NS_IF_RELEASE(mCurrentFocus); - if (nsnull != mCurrentTarget) { - mCurrentTarget->GetContent(&mCurrentFocus); - } + //XXX Do we need window related focus change stuff here? break; } return NS_OK; @@ -117,8 +126,14 @@ nsEventStateManager::PostHandleEvent(nsIPresContext& aPresContext, case NS_MOUSE_MIDDLE_BUTTON_DOWN: case NS_MOUSE_RIGHT_BUTTON_DOWN: { - if (nsnull != aEvent->widget) { - aEvent->widget->SetFocus(); + nsIContent* newFocus; + mCurrentTarget->GetContent(&newFocus); + if (newFocus) { + if (!ChangeFocus(newFocus, PR_TRUE)) { + if (nsnull != aEvent->widget) { + aEvent->widget->SetFocus(); + } + } } } //Break left out on purpose @@ -132,7 +147,8 @@ nsEventStateManager::PostHandleEvent(nsIPresContext& aPresContext, if (nsEventStatus_eConsumeNoDefault != aStatus) { switch(((nsKeyEvent*)aEvent)->keyCode) { case NS_VK_TAB: - ShiftFocus(); + //Shift focus forward or back depending on shift key + ShiftFocus(!((nsInputEvent*)aEvent)->isShift); aStatus = nsEventStatus_eConsumeNoDefault; break; case NS_VK_PAGE_DOWN: @@ -417,8 +433,28 @@ nsEventStateManager::DispatchKeyPressEvent(nsIPresContext& aPresContext, return ret; } +PRBool +nsEventStateManager::ChangeFocus(nsIContent* aFocus, PRBool aSetFocus) +{ + nsIFocusableContent *focusChange; + + if (NS_OK == aFocus->QueryInterface(kIFocusableContentIID,(void **)&focusChange)) { + if (aSetFocus) { + focusChange->SetFocus(mPresContext); + } + else { + focusChange->RemoveFocus(mPresContext); + } + NS_RELEASE(focusChange); + return PR_TRUE; + } + //XXX Need to deal with Object tag + + return PR_FALSE; +} + void -nsEventStateManager::ShiftFocus() +nsEventStateManager::ShiftFocus(PRBool forward) { if (nsnull == mPresContext) { return; @@ -439,36 +475,34 @@ nsEventStateManager::ShiftFocus() if (nsnull == mCurrentFocus) { return; } + mCurrentTabIndex = forward ? 1 : 0; } - nsIContent* next = GetNextTabbableContent(mCurrentFocus, nsnull, mCurrentFocus); + nsIContent* next = GetNextTabbableContent(mCurrentFocus, nsnull, mCurrentFocus, forward); if (nsnull == next) { NS_IF_RELEASE(mCurrentFocus); - //XXX pass focus up to webshellcontainer FocusAvailable + + //Pass focus up to nsIWebShellContainer FocusAvailable + nsISupports* container; + mPresContext->GetContainer(&container); + if (nsnull != container) { + nsIWebShell* webShell; + if (NS_OK == container->QueryInterface(kIWebShellIID, (void**)&webShell)) { + nsIWebShellContainer* webShellContainer; + webShell->GetContainer(webShellContainer); + if (nsnull != webShellContainer) { + webShellContainer->FocusAvailable(webShell); + NS_RELEASE(webShellContainer); + } + NS_RELEASE(webShell); + } + NS_RELEASE(container); + } return; } - nsIDOMHTMLAnchorElement *nextAnchor; - nsIDOMHTMLInputElement *nextInput; - nsIDOMHTMLSelectElement *nextSelect; - nsIDOMHTMLTextAreaElement *nextTextArea; - if (NS_OK == next->QueryInterface(kIDOMHTMLAnchorElementIID,(void **)&nextAnchor)) { - nextAnchor->Focus(); - NS_RELEASE(nextAnchor); - } - else if (NS_OK == next->QueryInterface(kIDOMHTMLInputElementIID,(void **)&nextInput)) { - nextInput->Focus(); - NS_RELEASE(nextInput); - } - else if (NS_OK == next->QueryInterface(kIDOMHTMLSelectElementIID,(void **)&nextSelect)) { - nextSelect->Focus(); - NS_RELEASE(nextSelect); - } - else if (NS_OK == next->QueryInterface(kIDOMHTMLTextAreaElementIID,(void **)&nextTextArea)) { - nextTextArea->Focus(); - NS_RELEASE(nextTextArea); - } + ChangeFocus(next, PR_TRUE); NS_IF_RELEASE(mCurrentFocus); mCurrentFocus = next; @@ -478,29 +512,31 @@ nsEventStateManager::ShiftFocus() * At some point this will need to be linked into HTML 4.0 tabindex */ nsIContent* -nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aChild, nsIContent* aTop) +nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aChild, nsIContent* aTop, PRBool forward) { PRInt32 count, index; aParent->ChildCount(count); if (nsnull != aChild) { aParent->IndexOf(aChild, index); - index += 1; + index += forward ? 1 : -1; } else { - index = 0; + index = forward ? 0 : count; } - for (;index < count;index++) { + for (;index < count && index >= 0;index += forward ? 1 : -1) { nsIContent* child; + aParent->ChildAt(index, child); - nsIContent* content = GetNextTabbableContent(child, nsnull, aTop); + nsIContent* content = GetNextTabbableContent(child, nsnull, aTop, forward); if (content != nsnull) { NS_IF_RELEASE(child); return content; } if (nsnull != child) { nsIAtom* tag; + PRInt32 tabIndex = -1; PRBool disabled = PR_TRUE; PRBool hidden = PR_FALSE; @@ -509,6 +545,7 @@ nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aCh nsIDOMHTMLInputElement *nextInput; if (NS_OK == child->QueryInterface(kIDOMHTMLInputElementIID,(void **)&nextInput)) { nextInput->GetDisabled(&disabled); + nextInput->GetTabIndex(&tabIndex); nsAutoString type; nextInput->GetType(type); @@ -522,6 +559,7 @@ nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aCh nsIDOMHTMLSelectElement *nextSelect; if (NS_OK == child->QueryInterface(kIDOMHTMLSelectElementIID,(void **)&nextSelect)) { nextSelect->GetDisabled(&disabled); + nextSelect->GetTabIndex(&tabIndex); NS_RELEASE(nextSelect); } } @@ -529,20 +567,48 @@ nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aCh nsIDOMHTMLTextAreaElement *nextTextArea; if (NS_OK == child->QueryInterface(kIDOMHTMLTextAreaElementIID,(void **)&nextTextArea)) { nextTextArea->GetDisabled(&disabled); + nextTextArea->GetTabIndex(&tabIndex); NS_RELEASE(nextTextArea); } } - //XXX Not all of these are focusable yet. - else if(nsHTMLAtoms::a==tag - //nsHTMLAtoms::area==tag || - //nsHTMLAtoms::button==tag || - //nsHTMLAtoms::object==tag - ) { + else if(nsHTMLAtoms::a==tag) { + nsIDOMHTMLAnchorElement *nextAnchor; + if (NS_OK == child->QueryInterface(kIDOMHTMLAnchorElementIID,(void **)&nextAnchor)) { + nextAnchor->GetTabIndex(&tabIndex); + NS_RELEASE(nextAnchor); + } + disabled = PR_FALSE; + } + else if(nsHTMLAtoms::button==tag) { + nsIDOMHTMLButtonElement *nextButton; + if (NS_OK == child->QueryInterface(kIDOMHTMLButtonElementIID,(void **)&nextButton)) { + nextButton->GetTabIndex(&tabIndex); + nextButton->GetDisabled(&disabled); + NS_RELEASE(nextButton); + } + } + else if(nsHTMLAtoms::area==tag) { + nsIDOMHTMLAreaElement *nextArea; + if (NS_OK == child->QueryInterface(kIDOMHTMLAreaElementIID,(void **)&nextArea)) { + nextArea->GetTabIndex(&tabIndex); + NS_RELEASE(nextArea); + } + disabled = PR_FALSE; + } + else if(nsHTMLAtoms::object==tag) { + nsIDOMHTMLObjectElement *nextObject; + if (NS_OK == child->QueryInterface(kIDOMHTMLObjectElementIID,(void **)&nextObject)) { + nextObject->GetTabIndex(&tabIndex); + NS_RELEASE(nextObject); + } disabled = PR_FALSE; } - if (!disabled && !hidden) { + //TabIndex not set (-1) treated at same level as set to 0 + tabIndex = tabIndex < 0 ? 0 : tabIndex; + + if (!disabled && !hidden && mCurrentTabIndex == tabIndex) { return child; } NS_RELEASE(child); @@ -553,15 +619,56 @@ nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aCh nsIContent* nextParent; aParent->GetParent(nextParent); if (nsnull != nextParent) { - nsIContent* content = GetNextTabbableContent(nextParent, aParent, nextParent); + nsIContent* content = GetNextTabbableContent(nextParent, aParent, nextParent, forward); NS_RELEASE(nextParent); return content; } + //Reached end of document + else { + //If already at lowest priority tab (0), end + if (0 == mCurrentTabIndex) { + return nsnull; + } + //else continue looking for next highest priority tab + mCurrentTabIndex = GetNextTabIndex(aParent, forward); + nsIContent* content = GetNextTabbableContent(aParent, nsnull, aParent, forward); + return content; + } } return nsnull; } +PRInt32 +nsEventStateManager::GetNextTabIndex(nsIContent* aParent, PRBool forward) +{ + + PRInt32 count, tabIndex = 0; + aParent->ChildCount(count); + + for (PRInt32 index = 0; index < count; index++) { + nsIContent* child; + PRInt32 childTabIndex; + + aParent->ChildAt(index, child); + childTabIndex = GetNextTabIndex(child, forward); + if (childTabIndex > mCurrentTabIndex && childTabIndex != tabIndex) { + tabIndex = (tabIndex == 0 || childTabIndex < tabIndex) ? childTabIndex : tabIndex; + } + + nsAutoString tabIndexStr; + child->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::tabindex, tabIndexStr); + PRInt32 ec, val = tabIndexStr.ToInteger(&ec); + if (NS_OK == ec && val > mCurrentTabIndex && val != tabIndex) { + tabIndex = (tabIndex == 0 || val < tabIndex) ? val : tabIndex; + } + NS_RELEASE(child); + } + + return tabIndex; +} + + NS_IMETHODIMP nsEventStateManager::GetEventTarget(nsIFrame **aFrame) { @@ -636,6 +743,51 @@ nsEventStateManager::SetHoverLink(nsIContent *aLink) return NS_OK; } +NS_IMETHODIMP +nsEventStateManager::SetFocusedContent(nsIContent *aContent) +{ + if (mCurrentFocus == aContent) { + return NS_OK; + } + + if (mCurrentFocus) { + ChangeFocus(mCurrentFocus, PR_FALSE); + + //fire blur + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + event.message = NS_BLUR_CONTENT; + + if (nsnull != mPresContext) { + mCurrentFocus->HandleDOMEvent(*mPresContext, &event, nsnull, DOM_EVENT_INIT, status); + } + NS_RELEASE(mCurrentFocus); + } + + //fire focus + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + event.message = NS_FOCUS_CONTENT; + + if (nsnull != mPresContext) { + aContent->HandleDOMEvent(*mPresContext, &event, nsnull, DOM_EVENT_INIT, status); + } + + nsAutoString tabIndex; + aContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::tabindex, tabIndex); + PRInt32 ec, val = tabIndex.ToInteger(&ec); + if (NS_OK == ec) { + mCurrentTabIndex = val; + } + + mCurrentFocus = aContent; + NS_IF_ADDREF(mCurrentFocus); + + return NS_OK; +} + nsresult NS_NewEventStateManager(nsIEventStateManager** aInstancePtrResult) { NS_PRECONDITION(nsnull != aInstancePtrResult, "nsnull ptr"); diff --git a/mozilla/content/events/src/nsEventStateManager.h b/mozilla/content/events/src/nsEventStateManager.h index dc751413381..ad9034577f5 100644 --- a/mozilla/content/events/src/nsEventStateManager.h +++ b/mozilla/content/events/src/nsEventStateManager.h @@ -54,13 +54,17 @@ public: NS_IMETHOD SetActiveLink(nsIContent *aLink); NS_IMETHOD SetHoverLink(nsIContent *aLink); + NS_IMETHOD SetFocusedContent(nsIContent *aContent); + protected: void UpdateCursor(nsIPresContext& aPresContext, nsPoint& aPoint, nsIFrame* aTargetFrame, nsEventStatus& aStatus); void GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIEvent* aEvent); NS_IMETHOD DispatchKeyPressEvent(nsIPresContext& aPresContext, nsKeyEvent *aEvent, nsEventStatus& aStatus); NS_IMETHOD CheckForAndDispatchClick(nsIPresContext& aPresContext, nsMouseEvent *aEvent, nsEventStatus& aStatus); - void ShiftFocus(); - nsIContent* GetNextTabbableContent(nsIContent* aParent, nsIContent* aChild, nsIContent* aTop); + PRBool ChangeFocus(nsIContent* aFocus, PRBool aSetFocus); + void ShiftFocus(PRBool foward); + nsIContent* GetNextTabbableContent(nsIContent* aParent, nsIContent* aChild, nsIContent* aTop, PRBool foward); + PRInt32 GetNextTabIndex(nsIContent* aParent, PRBool foward); //Any frames here must be checked for validity in ClearFrameRefs nsIFrame* mCurrentTarget; @@ -72,6 +76,7 @@ protected: nsIContent* mActiveLink; nsIContent* mHoverLink; nsIContent* mCurrentFocus; + PRInt32 mCurrentTabIndex; //Not refcnted nsIPresContext* mPresContext; diff --git a/mozilla/content/html/content/public/Makefile.in b/mozilla/content/html/content/public/Makefile.in index fbea75e448e..d4c04f9834b 100644 --- a/mozilla/content/html/content/public/Makefile.in +++ b/mozilla/content/html/content/public/Makefile.in @@ -25,6 +25,7 @@ include $(DEPTH)/config/autoconf.mk EXPORTS = \ nsIFormControl.h \ nsIForm.h \ + nsIFocusableContent.h \ $(NULL) EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) diff --git a/mozilla/content/html/content/public/makefile.win b/mozilla/content/html/content/public/makefile.win index 25324f5e049..29e6c8e6e4e 100644 --- a/mozilla/content/html/content/public/makefile.win +++ b/mozilla/content/html/content/public/makefile.win @@ -17,7 +17,7 @@ DEPTH=..\..\..\.. -EXPORTS=nsIFormControl.h nsIForm.h +EXPORTS=nsIFormControl.h nsIForm.h nsIFocusableContent.h MODULE=raptor diff --git a/mozilla/content/html/content/src/nsHTMLAnchorElement.cpp b/mozilla/content/html/content/src/nsHTMLAnchorElement.cpp index 05b75f76cdf..568621a515c 100644 --- a/mozilla/content/html/content/src/nsHTMLAnchorElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLAnchorElement.cpp @@ -28,6 +28,7 @@ #include "nsIPresContext.h" #include "nsINameSpaceManager.h" #include "nsIURL.h" +#include "nsIFocusableContent.h" #include "nsIEventStateManager.h" #include "nsDOMEvent.h" @@ -38,11 +39,13 @@ // custom frame static NS_DEFINE_IID(kIDOMHTMLAnchorElementIID, NS_IDOMHTMLANCHORELEMENT_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLAnchorElement : public nsIDOMHTMLAnchorElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, - public nsIHTMLContent + public nsIHTMLContent, + public nsIFocusableContent { public: nsHTMLAnchorElement(nsIAtom* aTag); @@ -100,6 +103,10 @@ public: // nsIHTMLContent NS_IMPL_IHTMLCONTENT_USING_GENERIC(mInner) + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLContainerElement mInner; }; @@ -142,6 +149,11 @@ nsHTMLAnchorElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) mRefCnt++; return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -183,6 +195,26 @@ nsHTMLAnchorElement::Focus() return NS_OK; } +NS_IMETHODIMP +nsHTMLAnchorElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX write me + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLAnchorElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX write me + return NS_OK; +} + NS_IMETHODIMP nsHTMLAnchorElement::StringToAttribute(nsIAtom* aAttribute, const nsString& aValue, @@ -261,7 +293,7 @@ nsHTMLAnchorElement::HandleDOMEvent(nsIPresContext& aPresContext, } break; - case NS_MOUSE_LEFT_BUTTON_UP: + case NS_MOUSE_LEFT_CLICK: { nsIEventStateManager *stateManager; nsLinkEventState linkState; diff --git a/mozilla/content/html/content/src/nsHTMLAreaElement.cpp b/mozilla/content/html/content/src/nsHTMLAreaElement.cpp index ff87d7ae910..562053de2a4 100644 --- a/mozilla/content/html/content/src/nsHTMLAreaElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLAreaElement.cpp @@ -26,13 +26,17 @@ #include "nsIStyleContext.h" #include "nsStyleConsts.h" #include "nsIPresContext.h" +#include "nsIFocusableContent.h" +#include "nsIEventStateManager.h" static NS_DEFINE_IID(kIDOMHTMLAreaElementIID, NS_IDOMHTMLAREAELEMENT_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLAreaElement : public nsIDOMHTMLAreaElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, - public nsIHTMLContent + public nsIHTMLContent, + public nsIFocusableContent { public: nsHTMLAreaElement(nsIAtom* aTag); @@ -80,6 +84,10 @@ public: // nsIHTMLContent NS_IMPL_IHTMLCONTENT_USING_GENERIC(mInner) + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLLeafElement mInner; }; @@ -122,6 +130,11 @@ nsHTMLAreaElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -191,6 +204,7 @@ nsHTMLAreaElement::HandleDOMEvent(nsIPresContext& aPresContext, NS_IMETHODIMP nsHTMLAreaElement::GetStyleHintForAttributeChange(const nsIAtom* aAttribute, PRInt32 *aHint) const + { if ((aAttribute == nsHTMLAtoms::alt) || (aAttribute == nsHTMLAtoms::coords) || @@ -208,5 +222,27 @@ nsHTMLAreaElement::GetStyleHintForAttributeChange(const nsIAtom* aAttribute, else { nsGenericHTMLElement::GetStyleHintForCommonAttributes(this, aAttribute, aHint); } + return NS_OK; } + +NS_IMETHODIMP +nsHTMLAreaElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX write me + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLAreaElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX write me + return NS_OK; +} + diff --git a/mozilla/content/html/content/src/nsHTMLButtonElement.cpp b/mozilla/content/html/content/src/nsHTMLButtonElement.cpp index f0c3505e7d0..e1d3021f423 100644 --- a/mozilla/content/html/content/src/nsHTMLButtonElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLButtonElement.cpp @@ -31,17 +31,20 @@ #include "nsIFormControl.h" #include "nsIForm.h" #include "nsIURL.h" +#include "nsIFocusableContent.h" #include "nsIEventStateManager.h" #include "nsDOMEvent.h" static NS_DEFINE_IID(kIDOMHTMLButtonElementIID, NS_IDOMHTMLBUTTONELEMENT_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLButtonElement : public nsIDOMHTMLButtonElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, public nsIHTMLContent, - public nsIFormControl + public nsIFormControl, + public nsIFocusableContent { public: nsHTMLButtonElement(nsIAtom* aTag); @@ -95,6 +98,10 @@ public: NS_IMETHOD SetWidget(nsIWidget* aWidget) { return NS_OK; }; NS_IMETHOD Init() { return NS_OK; } + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLContainerElement mInner; nsIForm* mForm; @@ -160,6 +167,11 @@ nsHTMLButtonElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -259,6 +271,26 @@ nsHTMLButtonElement::Focus() return NS_OK; } +NS_IMETHODIMP +nsHTMLButtonElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX write me + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLButtonElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX write me + return NS_OK; +} + static nsGenericHTMLElement::EnumTable kButtonTypeTable[] = { { "button", NS_FORM_BUTTON_BUTTON }, { "reset", NS_FORM_BUTTON_RESET }, diff --git a/mozilla/content/html/content/src/nsHTMLInputElement.cpp b/mozilla/content/html/content/src/nsHTMLInputElement.cpp index 280dc96921b..8dd56749d37 100644 --- a/mozilla/content/html/content/src/nsHTMLInputElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLInputElement.cpp @@ -41,6 +41,8 @@ #include "nsIPresShell.h" #include "nsIFormControlFrame.h" #include "nsIFrame.h" +#include "nsIFocusableContent.h" +#include "nsIEventStateManager.h" // XXX align=left, hspace, vspace, border? other nav4 attrs @@ -52,12 +54,14 @@ static NS_DEFINE_IID(kITextWidgetIID, NS_ITEXTWIDGET_IID); static NS_DEFINE_IID(kIRadioIID, NS_IRADIOBUTTON_IID); static NS_DEFINE_IID(kICheckButtonIID, NS_ICHECKBUTTON_IID); static NS_DEFINE_IID(kIFormControlFrameIID, NS_IFORMCONTROLFRAME_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLInputElement : public nsIDOMHTMLInputElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, public nsIHTMLContent, - public nsIFormControl + public nsIFormControl, + public nsIFocusableContent { public: nsHTMLInputElement(nsIAtom* aTag); @@ -133,6 +137,10 @@ public: NS_IMETHOD SetWidget(nsIWidget* aWidget); NS_IMETHOD Init() { return NS_OK; } + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLLeafElement mInner; nsIWidget* mWidget; // XXX this needs to go away when FindFrameWithContent is efficient @@ -206,6 +214,11 @@ nsHTMLInputElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -404,6 +417,29 @@ nsHTMLInputElement::Focus() return NS_OK; } +NS_IMETHODIMP +nsHTMLInputElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX Should focus only this presContext + Focus(); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLInputElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX Should focus only this presContext + Blur(); + return NS_OK; +} + + NS_IMETHODIMP nsHTMLInputElement::Select() { diff --git a/mozilla/content/html/content/src/nsHTMLSelectElement.cpp b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp index 73c0c8d1e8c..5bc62c42bb8 100644 --- a/mozilla/content/html/content/src/nsHTMLSelectElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp @@ -33,6 +33,8 @@ #include "nsIWidget.h" #include "nsIDOMHTMLCollection.h" #include "nsIDOMHTMLOptionElement.h" +#include "nsIFocusableContent.h" +#include "nsIEventStateManager.h" // Notify/query select frame for selectedIndex #include "nsIDocument.h" @@ -46,6 +48,7 @@ static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID); static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID); static NS_DEFINE_IID(kIFormIID, NS_IFORM_IID); static NS_DEFINE_IID(kIFormControlFrameIID, NS_IFORMCONTROLFRAME_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLSelectElement; @@ -77,7 +80,8 @@ class nsHTMLSelectElement : public nsIDOMHTMLSelectElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, public nsIHTMLContent, - public nsIFormControl + public nsIFormControl, + public nsIFocusableContent { public: nsHTMLSelectElement(nsIAtom* aTag); @@ -137,6 +141,9 @@ public: NS_IMETHOD SetWidget(nsIWidget* aWidget); NS_IMETHOD Init(); + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLContainerElement mInner; nsIWidget* mWidget; // XXX this needs to go away when FindFrameWithContent is efficient @@ -205,6 +212,11 @@ nsHTMLSelectElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) mRefCnt++; return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -398,6 +410,28 @@ nsHTMLSelectElement::Focus() return NS_OK; } +NS_IMETHODIMP +nsHTMLSelectElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX Should focus only this presContext + Focus(); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLSelectElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX Should focus only this presContext + Blur(); + return NS_OK; +} + NS_IMETHODIMP nsHTMLSelectElement::StringToAttribute(nsIAtom* aAttribute, const nsString& aValue, diff --git a/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp b/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp index 9cabe049902..83396e92cd0 100644 --- a/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp @@ -33,18 +33,22 @@ #include "nsITextAreaWidget.h" #include "nsIHTMLAttributes.h" #include "nsIFormControlFrame.h" +#include "nsIFocusableContent.h" +#include "nsIEventStateManager.h" static NS_DEFINE_IID(kIDOMHTMLTextAreaElementIID, NS_IDOMHTMLTEXTAREAELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID); static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID); static NS_DEFINE_IID(kIFormIID, NS_IFORM_IID); static NS_DEFINE_IID(kITextAreaWidgetIID, NS_ITEXTAREAWIDGET_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLTextAreaElement : public nsIDOMHTMLTextAreaElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, public nsIHTMLContent, - public nsIFormControl + public nsIFormControl, + public nsIFocusableContent { public: nsHTMLTextAreaElement(nsIAtom* aTag); @@ -105,6 +109,10 @@ public: NS_IMETHOD SetWidget(nsIWidget* aWidget); NS_IMETHOD Init() { return NS_OK; } + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLContainerElement mInner; nsIWidget* mWidget; // XXX this needs to go away when FindFrameWithContent is efficient @@ -163,6 +171,11 @@ nsHTMLTextAreaElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) mRefCnt++; return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -233,6 +246,29 @@ nsHTMLTextAreaElement::Focus() // XXX not tested return NS_OK; } + +NS_IMETHODIMP +nsHTMLTextAreaElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX Should focus only this presContext + Focus(); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLTextAreaElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX Should focus only this presContext + Blur(); + return NS_OK; +} + NS_IMETHODIMP nsHTMLTextAreaElement::Select() // XXX not tested { diff --git a/mozilla/docshell/base/nsWebShell.cpp b/mozilla/docshell/base/nsWebShell.cpp index a506101f272..85831932f2c 100644 --- a/mozilla/docshell/base/nsWebShell.cpp +++ b/mozilla/docshell/base/nsWebShell.cpp @@ -1638,7 +1638,32 @@ nsWebShell::FindWebShellWithName(const PRUnichar* aName, nsIWebShell*& aResult) NS_IMETHODIMP nsWebShell::FocusAvailable(nsIWebShell* aFocusedWebShell) { - //XXX Move focus to next child, or if on last child, call focus available on next container + //If the WebShell with focus is us, pass this up to container + if (this == aFocusedWebShell && nsnull != mContainer) { + mContainer->FocusAvailable(this); + } + + nsIWebShell* shell = nsnull; + + //Other wise, check children and move focus to next one + PRInt32 i, n = mChildren.Count(); + for (i = 0; i < n; i++) { + shell = (nsIWebShell*)mChildren.ElementAt(i); + if (shell == aFocusedWebShell) { + if (++i < n) { + NS_RELEASE(shell); + shell = (nsIWebShell*)mChildren.ElementAt(i); + shell->SetFocus(); + break; + } + else if (nsnull != mContainer) { + mContainer->FocusAvailable(this); + break; + } + } + } + NS_IF_RELEASE(shell); + return NS_OK; } //---------------------------------------------------------------------- diff --git a/mozilla/layout/base/src/nsDocument.cpp b/mozilla/layout/base/src/nsDocument.cpp index d250d79d5ca..fdafa68ec69 100644 --- a/mozilla/layout/base/src/nsDocument.cpp +++ b/mozilla/layout/base/src/nsDocument.cpp @@ -726,6 +726,8 @@ nsDocument::Reset(nsIURL *aURL) } if (nsnull != mRootContent) { + // Ensure that document is nsnull to allow validity checks on content + mRootContent->SetDocument(nsnull, PR_TRUE); ContentRemoved(nsnull, mRootContent, 0); NS_IF_RELEASE(mRootContent); } diff --git a/mozilla/layout/base/src/nsGenericElement.cpp b/mozilla/layout/base/src/nsGenericElement.cpp index f4f837cdef8..5580161c961 100644 --- a/mozilla/layout/base/src/nsGenericElement.cpp +++ b/mozilla/layout/base/src/nsGenericElement.cpp @@ -749,7 +749,7 @@ nsGenericElement::HandleDOMEvent(nsIPresContext& aPresContext, } //Bubbling stage - if ((DOM_EVENT_CAPTURE != aFlags) && (mParent != nsnull)) { + if ((DOM_EVENT_CAPTURE != aFlags) && (mParent != nsnull) && (mDocument != nsnull)) { ret = mParent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, DOM_EVENT_BUBBLE, aEventStatus); } diff --git a/mozilla/layout/events/public/nsIEventStateManager.h b/mozilla/layout/events/public/nsIEventStateManager.h index e6cec3dfbd0..9d529c4db75 100644 --- a/mozilla/layout/events/public/nsIEventStateManager.h +++ b/mozilla/layout/events/public/nsIEventStateManager.h @@ -64,6 +64,8 @@ public: NS_IMETHOD GetLinkState(nsIContent *aLink, nsLinkEventState& aState) = 0; NS_IMETHOD SetActiveLink(nsIContent *aLink) = 0; NS_IMETHOD SetHoverLink(nsIContent *aLink) = 0; + + NS_IMETHOD SetFocusedContent(nsIContent *aContent) = 0; }; #endif // nsIEventStateManager_h__ diff --git a/mozilla/layout/events/src/Makefile.in b/mozilla/layout/events/src/Makefile.in index 2daf92c43f8..f67b06aa5fd 100644 --- a/mozilla/layout/events/src/Makefile.in +++ b/mozilla/layout/events/src/Makefile.in @@ -44,7 +44,7 @@ EXPORTS = \ EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) -REQUIRES = xpcom raptor dom js +REQUIRES = xpcom raptor dom js netlib include $(topsrcdir)/config/config.mk diff --git a/mozilla/layout/events/src/makefile.win b/mozilla/layout/events/src/makefile.win index 368f09ea6b4..2d30f4c3eb6 100644 --- a/mozilla/layout/events/src/makefile.win +++ b/mozilla/layout/events/src/makefile.win @@ -42,7 +42,7 @@ CPP_OBJS= .\$(OBJDIR)\nsEventListenerManager.obj \ EXPORTS= nsEventListenerManager.h nsEventStateManager.h nsDOMEvent.h nsDOMEventsIIDs.h LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor \ - -I$(PUBLIC)\dom -I$(PUBLIC)\js -I..\..\html\base\src + -I$(PUBLIC)\dom -I$(PUBLIC)\js -I..\..\html\base\src -I$(PUBLIC)\netlib LCFLAGS = \ $(LCFLAGS) \ diff --git a/mozilla/layout/events/src/nsEventStateManager.cpp b/mozilla/layout/events/src/nsEventStateManager.cpp index ebf2233dbbb..f9ba669cc50 100644 --- a/mozilla/layout/events/src/nsEventStateManager.cpp +++ b/mozilla/layout/events/src/nsEventStateManager.cpp @@ -31,6 +31,12 @@ #include "nsIDOMHTMLInputElement.h" #include "nsIDOMHTMLSelectElement.h" #include "nsIDOMHTMLTextAreaElement.h" +#include "nsIDOMHTMLAreaElement.h" +#include "nsIDOMHTMLButtonElement.h" +#include "nsIDOMHTMLObjectElement.h" +#include "nsINameSpaceManager.h" // for kNameSpaceID_HTML +#include "nsIWebShell.h" +#include "nsIFocusableContent.h" static NS_DEFINE_IID(kIEventStateManagerIID, NS_IEVENTSTATEMANAGER_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); @@ -38,6 +44,11 @@ static NS_DEFINE_IID(kIDOMHTMLAnchorElementIID, NS_IDOMHTMLANCHORELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLInputElementIID, NS_IDOMHTMLINPUTELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLTextAreaElementIID, NS_IDOMHTMLTEXTAREAELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLAreaElementIID, NS_IDOMHTMLAREAELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLObjectElementIID, NS_IDOMHTMLOBJECTELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLButtonElementIID, NS_IDOMHTMLBUTTONELEMENT_IID); +static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); nsEventStateManager::nsEventStateManager() { mLastMouseOverFrame = nsnull; @@ -51,6 +62,7 @@ nsEventStateManager::nsEventStateManager() { mCurrentFocus = nsnull; mDocument = nsnull; mPresContext = nsnull; + mCurrentTabIndex = 0; NS_INIT_REFCNT(); } @@ -89,10 +101,7 @@ nsEventStateManager::PreHandleEvent(nsIPresContext& aPresContext, //GenerateMouseEnterExit(aPresContext, aEvent, aTargetFrame); break; case NS_GOTFOCUS: - NS_IF_RELEASE(mCurrentFocus); - if (nsnull != mCurrentTarget) { - mCurrentTarget->GetContent(&mCurrentFocus); - } + //XXX Do we need window related focus change stuff here? break; } return NS_OK; @@ -117,8 +126,14 @@ nsEventStateManager::PostHandleEvent(nsIPresContext& aPresContext, case NS_MOUSE_MIDDLE_BUTTON_DOWN: case NS_MOUSE_RIGHT_BUTTON_DOWN: { - if (nsnull != aEvent->widget) { - aEvent->widget->SetFocus(); + nsIContent* newFocus; + mCurrentTarget->GetContent(&newFocus); + if (newFocus) { + if (!ChangeFocus(newFocus, PR_TRUE)) { + if (nsnull != aEvent->widget) { + aEvent->widget->SetFocus(); + } + } } } //Break left out on purpose @@ -132,7 +147,8 @@ nsEventStateManager::PostHandleEvent(nsIPresContext& aPresContext, if (nsEventStatus_eConsumeNoDefault != aStatus) { switch(((nsKeyEvent*)aEvent)->keyCode) { case NS_VK_TAB: - ShiftFocus(); + //Shift focus forward or back depending on shift key + ShiftFocus(!((nsInputEvent*)aEvent)->isShift); aStatus = nsEventStatus_eConsumeNoDefault; break; case NS_VK_PAGE_DOWN: @@ -417,8 +433,28 @@ nsEventStateManager::DispatchKeyPressEvent(nsIPresContext& aPresContext, return ret; } +PRBool +nsEventStateManager::ChangeFocus(nsIContent* aFocus, PRBool aSetFocus) +{ + nsIFocusableContent *focusChange; + + if (NS_OK == aFocus->QueryInterface(kIFocusableContentIID,(void **)&focusChange)) { + if (aSetFocus) { + focusChange->SetFocus(mPresContext); + } + else { + focusChange->RemoveFocus(mPresContext); + } + NS_RELEASE(focusChange); + return PR_TRUE; + } + //XXX Need to deal with Object tag + + return PR_FALSE; +} + void -nsEventStateManager::ShiftFocus() +nsEventStateManager::ShiftFocus(PRBool forward) { if (nsnull == mPresContext) { return; @@ -439,36 +475,34 @@ nsEventStateManager::ShiftFocus() if (nsnull == mCurrentFocus) { return; } + mCurrentTabIndex = forward ? 1 : 0; } - nsIContent* next = GetNextTabbableContent(mCurrentFocus, nsnull, mCurrentFocus); + nsIContent* next = GetNextTabbableContent(mCurrentFocus, nsnull, mCurrentFocus, forward); if (nsnull == next) { NS_IF_RELEASE(mCurrentFocus); - //XXX pass focus up to webshellcontainer FocusAvailable + + //Pass focus up to nsIWebShellContainer FocusAvailable + nsISupports* container; + mPresContext->GetContainer(&container); + if (nsnull != container) { + nsIWebShell* webShell; + if (NS_OK == container->QueryInterface(kIWebShellIID, (void**)&webShell)) { + nsIWebShellContainer* webShellContainer; + webShell->GetContainer(webShellContainer); + if (nsnull != webShellContainer) { + webShellContainer->FocusAvailable(webShell); + NS_RELEASE(webShellContainer); + } + NS_RELEASE(webShell); + } + NS_RELEASE(container); + } return; } - nsIDOMHTMLAnchorElement *nextAnchor; - nsIDOMHTMLInputElement *nextInput; - nsIDOMHTMLSelectElement *nextSelect; - nsIDOMHTMLTextAreaElement *nextTextArea; - if (NS_OK == next->QueryInterface(kIDOMHTMLAnchorElementIID,(void **)&nextAnchor)) { - nextAnchor->Focus(); - NS_RELEASE(nextAnchor); - } - else if (NS_OK == next->QueryInterface(kIDOMHTMLInputElementIID,(void **)&nextInput)) { - nextInput->Focus(); - NS_RELEASE(nextInput); - } - else if (NS_OK == next->QueryInterface(kIDOMHTMLSelectElementIID,(void **)&nextSelect)) { - nextSelect->Focus(); - NS_RELEASE(nextSelect); - } - else if (NS_OK == next->QueryInterface(kIDOMHTMLTextAreaElementIID,(void **)&nextTextArea)) { - nextTextArea->Focus(); - NS_RELEASE(nextTextArea); - } + ChangeFocus(next, PR_TRUE); NS_IF_RELEASE(mCurrentFocus); mCurrentFocus = next; @@ -478,29 +512,31 @@ nsEventStateManager::ShiftFocus() * At some point this will need to be linked into HTML 4.0 tabindex */ nsIContent* -nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aChild, nsIContent* aTop) +nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aChild, nsIContent* aTop, PRBool forward) { PRInt32 count, index; aParent->ChildCount(count); if (nsnull != aChild) { aParent->IndexOf(aChild, index); - index += 1; + index += forward ? 1 : -1; } else { - index = 0; + index = forward ? 0 : count; } - for (;index < count;index++) { + for (;index < count && index >= 0;index += forward ? 1 : -1) { nsIContent* child; + aParent->ChildAt(index, child); - nsIContent* content = GetNextTabbableContent(child, nsnull, aTop); + nsIContent* content = GetNextTabbableContent(child, nsnull, aTop, forward); if (content != nsnull) { NS_IF_RELEASE(child); return content; } if (nsnull != child) { nsIAtom* tag; + PRInt32 tabIndex = -1; PRBool disabled = PR_TRUE; PRBool hidden = PR_FALSE; @@ -509,6 +545,7 @@ nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aCh nsIDOMHTMLInputElement *nextInput; if (NS_OK == child->QueryInterface(kIDOMHTMLInputElementIID,(void **)&nextInput)) { nextInput->GetDisabled(&disabled); + nextInput->GetTabIndex(&tabIndex); nsAutoString type; nextInput->GetType(type); @@ -522,6 +559,7 @@ nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aCh nsIDOMHTMLSelectElement *nextSelect; if (NS_OK == child->QueryInterface(kIDOMHTMLSelectElementIID,(void **)&nextSelect)) { nextSelect->GetDisabled(&disabled); + nextSelect->GetTabIndex(&tabIndex); NS_RELEASE(nextSelect); } } @@ -529,20 +567,48 @@ nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aCh nsIDOMHTMLTextAreaElement *nextTextArea; if (NS_OK == child->QueryInterface(kIDOMHTMLTextAreaElementIID,(void **)&nextTextArea)) { nextTextArea->GetDisabled(&disabled); + nextTextArea->GetTabIndex(&tabIndex); NS_RELEASE(nextTextArea); } } - //XXX Not all of these are focusable yet. - else if(nsHTMLAtoms::a==tag - //nsHTMLAtoms::area==tag || - //nsHTMLAtoms::button==tag || - //nsHTMLAtoms::object==tag - ) { + else if(nsHTMLAtoms::a==tag) { + nsIDOMHTMLAnchorElement *nextAnchor; + if (NS_OK == child->QueryInterface(kIDOMHTMLAnchorElementIID,(void **)&nextAnchor)) { + nextAnchor->GetTabIndex(&tabIndex); + NS_RELEASE(nextAnchor); + } + disabled = PR_FALSE; + } + else if(nsHTMLAtoms::button==tag) { + nsIDOMHTMLButtonElement *nextButton; + if (NS_OK == child->QueryInterface(kIDOMHTMLButtonElementIID,(void **)&nextButton)) { + nextButton->GetTabIndex(&tabIndex); + nextButton->GetDisabled(&disabled); + NS_RELEASE(nextButton); + } + } + else if(nsHTMLAtoms::area==tag) { + nsIDOMHTMLAreaElement *nextArea; + if (NS_OK == child->QueryInterface(kIDOMHTMLAreaElementIID,(void **)&nextArea)) { + nextArea->GetTabIndex(&tabIndex); + NS_RELEASE(nextArea); + } + disabled = PR_FALSE; + } + else if(nsHTMLAtoms::object==tag) { + nsIDOMHTMLObjectElement *nextObject; + if (NS_OK == child->QueryInterface(kIDOMHTMLObjectElementIID,(void **)&nextObject)) { + nextObject->GetTabIndex(&tabIndex); + NS_RELEASE(nextObject); + } disabled = PR_FALSE; } - if (!disabled && !hidden) { + //TabIndex not set (-1) treated at same level as set to 0 + tabIndex = tabIndex < 0 ? 0 : tabIndex; + + if (!disabled && !hidden && mCurrentTabIndex == tabIndex) { return child; } NS_RELEASE(child); @@ -553,15 +619,56 @@ nsEventStateManager::GetNextTabbableContent(nsIContent* aParent, nsIContent* aCh nsIContent* nextParent; aParent->GetParent(nextParent); if (nsnull != nextParent) { - nsIContent* content = GetNextTabbableContent(nextParent, aParent, nextParent); + nsIContent* content = GetNextTabbableContent(nextParent, aParent, nextParent, forward); NS_RELEASE(nextParent); return content; } + //Reached end of document + else { + //If already at lowest priority tab (0), end + if (0 == mCurrentTabIndex) { + return nsnull; + } + //else continue looking for next highest priority tab + mCurrentTabIndex = GetNextTabIndex(aParent, forward); + nsIContent* content = GetNextTabbableContent(aParent, nsnull, aParent, forward); + return content; + } } return nsnull; } +PRInt32 +nsEventStateManager::GetNextTabIndex(nsIContent* aParent, PRBool forward) +{ + + PRInt32 count, tabIndex = 0; + aParent->ChildCount(count); + + for (PRInt32 index = 0; index < count; index++) { + nsIContent* child; + PRInt32 childTabIndex; + + aParent->ChildAt(index, child); + childTabIndex = GetNextTabIndex(child, forward); + if (childTabIndex > mCurrentTabIndex && childTabIndex != tabIndex) { + tabIndex = (tabIndex == 0 || childTabIndex < tabIndex) ? childTabIndex : tabIndex; + } + + nsAutoString tabIndexStr; + child->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::tabindex, tabIndexStr); + PRInt32 ec, val = tabIndexStr.ToInteger(&ec); + if (NS_OK == ec && val > mCurrentTabIndex && val != tabIndex) { + tabIndex = (tabIndex == 0 || val < tabIndex) ? val : tabIndex; + } + NS_RELEASE(child); + } + + return tabIndex; +} + + NS_IMETHODIMP nsEventStateManager::GetEventTarget(nsIFrame **aFrame) { @@ -636,6 +743,51 @@ nsEventStateManager::SetHoverLink(nsIContent *aLink) return NS_OK; } +NS_IMETHODIMP +nsEventStateManager::SetFocusedContent(nsIContent *aContent) +{ + if (mCurrentFocus == aContent) { + return NS_OK; + } + + if (mCurrentFocus) { + ChangeFocus(mCurrentFocus, PR_FALSE); + + //fire blur + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + event.message = NS_BLUR_CONTENT; + + if (nsnull != mPresContext) { + mCurrentFocus->HandleDOMEvent(*mPresContext, &event, nsnull, DOM_EVENT_INIT, status); + } + NS_RELEASE(mCurrentFocus); + } + + //fire focus + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + event.message = NS_FOCUS_CONTENT; + + if (nsnull != mPresContext) { + aContent->HandleDOMEvent(*mPresContext, &event, nsnull, DOM_EVENT_INIT, status); + } + + nsAutoString tabIndex; + aContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::tabindex, tabIndex); + PRInt32 ec, val = tabIndex.ToInteger(&ec); + if (NS_OK == ec) { + mCurrentTabIndex = val; + } + + mCurrentFocus = aContent; + NS_IF_ADDREF(mCurrentFocus); + + return NS_OK; +} + nsresult NS_NewEventStateManager(nsIEventStateManager** aInstancePtrResult) { NS_PRECONDITION(nsnull != aInstancePtrResult, "nsnull ptr"); diff --git a/mozilla/layout/events/src/nsEventStateManager.h b/mozilla/layout/events/src/nsEventStateManager.h index dc751413381..ad9034577f5 100644 --- a/mozilla/layout/events/src/nsEventStateManager.h +++ b/mozilla/layout/events/src/nsEventStateManager.h @@ -54,13 +54,17 @@ public: NS_IMETHOD SetActiveLink(nsIContent *aLink); NS_IMETHOD SetHoverLink(nsIContent *aLink); + NS_IMETHOD SetFocusedContent(nsIContent *aContent); + protected: void UpdateCursor(nsIPresContext& aPresContext, nsPoint& aPoint, nsIFrame* aTargetFrame, nsEventStatus& aStatus); void GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIEvent* aEvent); NS_IMETHOD DispatchKeyPressEvent(nsIPresContext& aPresContext, nsKeyEvent *aEvent, nsEventStatus& aStatus); NS_IMETHOD CheckForAndDispatchClick(nsIPresContext& aPresContext, nsMouseEvent *aEvent, nsEventStatus& aStatus); - void ShiftFocus(); - nsIContent* GetNextTabbableContent(nsIContent* aParent, nsIContent* aChild, nsIContent* aTop); + PRBool ChangeFocus(nsIContent* aFocus, PRBool aSetFocus); + void ShiftFocus(PRBool foward); + nsIContent* GetNextTabbableContent(nsIContent* aParent, nsIContent* aChild, nsIContent* aTop, PRBool foward); + PRInt32 GetNextTabIndex(nsIContent* aParent, PRBool foward); //Any frames here must be checked for validity in ClearFrameRefs nsIFrame* mCurrentTarget; @@ -72,6 +76,7 @@ protected: nsIContent* mActiveLink; nsIContent* mHoverLink; nsIContent* mCurrentFocus; + PRInt32 mCurrentTabIndex; //Not refcnted nsIPresContext* mPresContext; diff --git a/mozilla/layout/forms/nsHTMLButtonControlFrame.cpp b/mozilla/layout/forms/nsHTMLButtonControlFrame.cpp index 76deb2a3e5c..5e58f919c29 100644 --- a/mozilla/layout/forms/nsHTMLButtonControlFrame.cpp +++ b/mozilla/layout/forms/nsHTMLButtonControlFrame.cpp @@ -444,7 +444,7 @@ nsHTMLButtonControlFrame::ShiftContents(nsIPresContext& aPresContext, PRBool aDo mStyleContext->RecalcAutomaticData(&aPresContext); nsRect rect(0, 0, mRect.width, mRect.height); - ReflowTemp(aPresContext, this, rect); + //ReflowTemp(aPresContext, this, rect); } void diff --git a/mozilla/layout/html/content/public/Makefile.in b/mozilla/layout/html/content/public/Makefile.in index fbea75e448e..d4c04f9834b 100644 --- a/mozilla/layout/html/content/public/Makefile.in +++ b/mozilla/layout/html/content/public/Makefile.in @@ -25,6 +25,7 @@ include $(DEPTH)/config/autoconf.mk EXPORTS = \ nsIFormControl.h \ nsIForm.h \ + nsIFocusableContent.h \ $(NULL) EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) diff --git a/mozilla/layout/html/content/public/makefile.win b/mozilla/layout/html/content/public/makefile.win index 25324f5e049..29e6c8e6e4e 100644 --- a/mozilla/layout/html/content/public/makefile.win +++ b/mozilla/layout/html/content/public/makefile.win @@ -17,7 +17,7 @@ DEPTH=..\..\..\.. -EXPORTS=nsIFormControl.h nsIForm.h +EXPORTS=nsIFormControl.h nsIForm.h nsIFocusableContent.h MODULE=raptor diff --git a/mozilla/layout/html/content/src/nsHTMLAnchorElement.cpp b/mozilla/layout/html/content/src/nsHTMLAnchorElement.cpp index 05b75f76cdf..568621a515c 100644 --- a/mozilla/layout/html/content/src/nsHTMLAnchorElement.cpp +++ b/mozilla/layout/html/content/src/nsHTMLAnchorElement.cpp @@ -28,6 +28,7 @@ #include "nsIPresContext.h" #include "nsINameSpaceManager.h" #include "nsIURL.h" +#include "nsIFocusableContent.h" #include "nsIEventStateManager.h" #include "nsDOMEvent.h" @@ -38,11 +39,13 @@ // custom frame static NS_DEFINE_IID(kIDOMHTMLAnchorElementIID, NS_IDOMHTMLANCHORELEMENT_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLAnchorElement : public nsIDOMHTMLAnchorElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, - public nsIHTMLContent + public nsIHTMLContent, + public nsIFocusableContent { public: nsHTMLAnchorElement(nsIAtom* aTag); @@ -100,6 +103,10 @@ public: // nsIHTMLContent NS_IMPL_IHTMLCONTENT_USING_GENERIC(mInner) + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLContainerElement mInner; }; @@ -142,6 +149,11 @@ nsHTMLAnchorElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) mRefCnt++; return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -183,6 +195,26 @@ nsHTMLAnchorElement::Focus() return NS_OK; } +NS_IMETHODIMP +nsHTMLAnchorElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX write me + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLAnchorElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX write me + return NS_OK; +} + NS_IMETHODIMP nsHTMLAnchorElement::StringToAttribute(nsIAtom* aAttribute, const nsString& aValue, @@ -261,7 +293,7 @@ nsHTMLAnchorElement::HandleDOMEvent(nsIPresContext& aPresContext, } break; - case NS_MOUSE_LEFT_BUTTON_UP: + case NS_MOUSE_LEFT_CLICK: { nsIEventStateManager *stateManager; nsLinkEventState linkState; diff --git a/mozilla/layout/html/content/src/nsHTMLAreaElement.cpp b/mozilla/layout/html/content/src/nsHTMLAreaElement.cpp index ff87d7ae910..562053de2a4 100644 --- a/mozilla/layout/html/content/src/nsHTMLAreaElement.cpp +++ b/mozilla/layout/html/content/src/nsHTMLAreaElement.cpp @@ -26,13 +26,17 @@ #include "nsIStyleContext.h" #include "nsStyleConsts.h" #include "nsIPresContext.h" +#include "nsIFocusableContent.h" +#include "nsIEventStateManager.h" static NS_DEFINE_IID(kIDOMHTMLAreaElementIID, NS_IDOMHTMLAREAELEMENT_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLAreaElement : public nsIDOMHTMLAreaElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, - public nsIHTMLContent + public nsIHTMLContent, + public nsIFocusableContent { public: nsHTMLAreaElement(nsIAtom* aTag); @@ -80,6 +84,10 @@ public: // nsIHTMLContent NS_IMPL_IHTMLCONTENT_USING_GENERIC(mInner) + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLLeafElement mInner; }; @@ -122,6 +130,11 @@ nsHTMLAreaElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -191,6 +204,7 @@ nsHTMLAreaElement::HandleDOMEvent(nsIPresContext& aPresContext, NS_IMETHODIMP nsHTMLAreaElement::GetStyleHintForAttributeChange(const nsIAtom* aAttribute, PRInt32 *aHint) const + { if ((aAttribute == nsHTMLAtoms::alt) || (aAttribute == nsHTMLAtoms::coords) || @@ -208,5 +222,27 @@ nsHTMLAreaElement::GetStyleHintForAttributeChange(const nsIAtom* aAttribute, else { nsGenericHTMLElement::GetStyleHintForCommonAttributes(this, aAttribute, aHint); } + return NS_OK; } + +NS_IMETHODIMP +nsHTMLAreaElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX write me + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLAreaElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX write me + return NS_OK; +} + diff --git a/mozilla/layout/html/content/src/nsHTMLButtonElement.cpp b/mozilla/layout/html/content/src/nsHTMLButtonElement.cpp index f0c3505e7d0..e1d3021f423 100644 --- a/mozilla/layout/html/content/src/nsHTMLButtonElement.cpp +++ b/mozilla/layout/html/content/src/nsHTMLButtonElement.cpp @@ -31,17 +31,20 @@ #include "nsIFormControl.h" #include "nsIForm.h" #include "nsIURL.h" +#include "nsIFocusableContent.h" #include "nsIEventStateManager.h" #include "nsDOMEvent.h" static NS_DEFINE_IID(kIDOMHTMLButtonElementIID, NS_IDOMHTMLBUTTONELEMENT_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLButtonElement : public nsIDOMHTMLButtonElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, public nsIHTMLContent, - public nsIFormControl + public nsIFormControl, + public nsIFocusableContent { public: nsHTMLButtonElement(nsIAtom* aTag); @@ -95,6 +98,10 @@ public: NS_IMETHOD SetWidget(nsIWidget* aWidget) { return NS_OK; }; NS_IMETHOD Init() { return NS_OK; } + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLContainerElement mInner; nsIForm* mForm; @@ -160,6 +167,11 @@ nsHTMLButtonElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -259,6 +271,26 @@ nsHTMLButtonElement::Focus() return NS_OK; } +NS_IMETHODIMP +nsHTMLButtonElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX write me + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLButtonElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX write me + return NS_OK; +} + static nsGenericHTMLElement::EnumTable kButtonTypeTable[] = { { "button", NS_FORM_BUTTON_BUTTON }, { "reset", NS_FORM_BUTTON_RESET }, diff --git a/mozilla/layout/html/content/src/nsHTMLInputElement.cpp b/mozilla/layout/html/content/src/nsHTMLInputElement.cpp index 280dc96921b..8dd56749d37 100644 --- a/mozilla/layout/html/content/src/nsHTMLInputElement.cpp +++ b/mozilla/layout/html/content/src/nsHTMLInputElement.cpp @@ -41,6 +41,8 @@ #include "nsIPresShell.h" #include "nsIFormControlFrame.h" #include "nsIFrame.h" +#include "nsIFocusableContent.h" +#include "nsIEventStateManager.h" // XXX align=left, hspace, vspace, border? other nav4 attrs @@ -52,12 +54,14 @@ static NS_DEFINE_IID(kITextWidgetIID, NS_ITEXTWIDGET_IID); static NS_DEFINE_IID(kIRadioIID, NS_IRADIOBUTTON_IID); static NS_DEFINE_IID(kICheckButtonIID, NS_ICHECKBUTTON_IID); static NS_DEFINE_IID(kIFormControlFrameIID, NS_IFORMCONTROLFRAME_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLInputElement : public nsIDOMHTMLInputElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, public nsIHTMLContent, - public nsIFormControl + public nsIFormControl, + public nsIFocusableContent { public: nsHTMLInputElement(nsIAtom* aTag); @@ -133,6 +137,10 @@ public: NS_IMETHOD SetWidget(nsIWidget* aWidget); NS_IMETHOD Init() { return NS_OK; } + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLLeafElement mInner; nsIWidget* mWidget; // XXX this needs to go away when FindFrameWithContent is efficient @@ -206,6 +214,11 @@ nsHTMLInputElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -404,6 +417,29 @@ nsHTMLInputElement::Focus() return NS_OK; } +NS_IMETHODIMP +nsHTMLInputElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX Should focus only this presContext + Focus(); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLInputElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX Should focus only this presContext + Blur(); + return NS_OK; +} + + NS_IMETHODIMP nsHTMLInputElement::Select() { diff --git a/mozilla/layout/html/content/src/nsHTMLSelectElement.cpp b/mozilla/layout/html/content/src/nsHTMLSelectElement.cpp index 73c0c8d1e8c..5bc62c42bb8 100644 --- a/mozilla/layout/html/content/src/nsHTMLSelectElement.cpp +++ b/mozilla/layout/html/content/src/nsHTMLSelectElement.cpp @@ -33,6 +33,8 @@ #include "nsIWidget.h" #include "nsIDOMHTMLCollection.h" #include "nsIDOMHTMLOptionElement.h" +#include "nsIFocusableContent.h" +#include "nsIEventStateManager.h" // Notify/query select frame for selectedIndex #include "nsIDocument.h" @@ -46,6 +48,7 @@ static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID); static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID); static NS_DEFINE_IID(kIFormIID, NS_IFORM_IID); static NS_DEFINE_IID(kIFormControlFrameIID, NS_IFORMCONTROLFRAME_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLSelectElement; @@ -77,7 +80,8 @@ class nsHTMLSelectElement : public nsIDOMHTMLSelectElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, public nsIHTMLContent, - public nsIFormControl + public nsIFormControl, + public nsIFocusableContent { public: nsHTMLSelectElement(nsIAtom* aTag); @@ -137,6 +141,9 @@ public: NS_IMETHOD SetWidget(nsIWidget* aWidget); NS_IMETHOD Init(); + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLContainerElement mInner; nsIWidget* mWidget; // XXX this needs to go away when FindFrameWithContent is efficient @@ -205,6 +212,11 @@ nsHTMLSelectElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) mRefCnt++; return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -398,6 +410,28 @@ nsHTMLSelectElement::Focus() return NS_OK; } +NS_IMETHODIMP +nsHTMLSelectElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX Should focus only this presContext + Focus(); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLSelectElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX Should focus only this presContext + Blur(); + return NS_OK; +} + NS_IMETHODIMP nsHTMLSelectElement::StringToAttribute(nsIAtom* aAttribute, const nsString& aValue, diff --git a/mozilla/layout/html/content/src/nsHTMLTextAreaElement.cpp b/mozilla/layout/html/content/src/nsHTMLTextAreaElement.cpp index 9cabe049902..83396e92cd0 100644 --- a/mozilla/layout/html/content/src/nsHTMLTextAreaElement.cpp +++ b/mozilla/layout/html/content/src/nsHTMLTextAreaElement.cpp @@ -33,18 +33,22 @@ #include "nsITextAreaWidget.h" #include "nsIHTMLAttributes.h" #include "nsIFormControlFrame.h" +#include "nsIFocusableContent.h" +#include "nsIEventStateManager.h" static NS_DEFINE_IID(kIDOMHTMLTextAreaElementIID, NS_IDOMHTMLTEXTAREAELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID); static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID); static NS_DEFINE_IID(kIFormIID, NS_IFORM_IID); static NS_DEFINE_IID(kITextAreaWidgetIID, NS_ITEXTAREAWIDGET_IID); +static NS_DEFINE_IID(kIFocusableContentIID, NS_IFOCUSABLECONTENT_IID); class nsHTMLTextAreaElement : public nsIDOMHTMLTextAreaElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, public nsIHTMLContent, - public nsIFormControl + public nsIFormControl, + public nsIFocusableContent { public: nsHTMLTextAreaElement(nsIAtom* aTag); @@ -105,6 +109,10 @@ public: NS_IMETHOD SetWidget(nsIWidget* aWidget); NS_IMETHOD Init() { return NS_OK; } + // nsIFocusableContent + NS_IMETHOD SetFocus(nsIPresContext* aPresContext); + NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext); + protected: nsGenericHTMLContainerElement mInner; nsIWidget* mWidget; // XXX this needs to go away when FindFrameWithContent is efficient @@ -163,6 +171,11 @@ nsHTMLTextAreaElement::QueryInterface(REFNSIID aIID, void** aInstancePtr) mRefCnt++; return NS_OK; } + else if (aIID.Equals(kIFocusableContentIID)) { + *aInstancePtr = (void*)(nsIFocusableContent*) this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -233,6 +246,29 @@ nsHTMLTextAreaElement::Focus() // XXX not tested return NS_OK; } + +NS_IMETHODIMP +nsHTMLTextAreaElement::SetFocus(nsIPresContext* aPresContext) +{ + nsIEventStateManager* esm; + if (NS_OK == aPresContext->GetEventStateManager(&esm)) { + esm->SetFocusedContent(this); + NS_RELEASE(esm); + } + + // XXX Should focus only this presContext + Focus(); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLTextAreaElement::RemoveFocus(nsIPresContext* aPresContext) +{ + // XXX Should focus only this presContext + Blur(); + return NS_OK; +} + NS_IMETHODIMP nsHTMLTextAreaElement::Select() // XXX not tested { diff --git a/mozilla/layout/html/forms/src/nsHTMLButtonControlFrame.cpp b/mozilla/layout/html/forms/src/nsHTMLButtonControlFrame.cpp index 76deb2a3e5c..5e58f919c29 100644 --- a/mozilla/layout/html/forms/src/nsHTMLButtonControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsHTMLButtonControlFrame.cpp @@ -444,7 +444,7 @@ nsHTMLButtonControlFrame::ShiftContents(nsIPresContext& aPresContext, PRBool aDo mStyleContext->RecalcAutomaticData(&aPresContext); nsRect rect(0, 0, mRect.width, mRect.height); - ReflowTemp(aPresContext, this, rect); + //ReflowTemp(aPresContext, this, rect); } void diff --git a/mozilla/webshell/src/nsWebShell.cpp b/mozilla/webshell/src/nsWebShell.cpp index a506101f272..85831932f2c 100644 --- a/mozilla/webshell/src/nsWebShell.cpp +++ b/mozilla/webshell/src/nsWebShell.cpp @@ -1638,7 +1638,32 @@ nsWebShell::FindWebShellWithName(const PRUnichar* aName, nsIWebShell*& aResult) NS_IMETHODIMP nsWebShell::FocusAvailable(nsIWebShell* aFocusedWebShell) { - //XXX Move focus to next child, or if on last child, call focus available on next container + //If the WebShell with focus is us, pass this up to container + if (this == aFocusedWebShell && nsnull != mContainer) { + mContainer->FocusAvailable(this); + } + + nsIWebShell* shell = nsnull; + + //Other wise, check children and move focus to next one + PRInt32 i, n = mChildren.Count(); + for (i = 0; i < n; i++) { + shell = (nsIWebShell*)mChildren.ElementAt(i); + if (shell == aFocusedWebShell) { + if (++i < n) { + NS_RELEASE(shell); + shell = (nsIWebShell*)mChildren.ElementAt(i); + shell->SetFocus(); + break; + } + else if (nsnull != mContainer) { + mContainer->FocusAvailable(this); + break; + } + } + } + NS_IF_RELEASE(shell); + return NS_OK; } //---------------------------------------------------------------------- diff --git a/mozilla/widget/public/nsGUIEvent.h b/mozilla/widget/public/nsGUIEvent.h index 2490e042a75..02fcba8bf0f 100644 --- a/mozilla/widget/public/nsGUIEvent.h +++ b/mozilla/widget/public/nsGUIEvent.h @@ -242,6 +242,12 @@ struct nsMenuEvent : public nsGUIEvent { #define NS_FORM_SUBMIT (NS_FORM_EVENT_START) #define NS_FORM_RESET (NS_FORM_EVENT_START + 1) #define NS_FORM_CHANGE (NS_FORM_EVENT_START + 2) + +//Need separate focus/blur notifications for non-native widgets +#define NS_FOCUS_EVENT_START 1300 +#define NS_FOCUS_CONTENT (NS_FOCUS_EVENT_START) +#define NS_BLUR_CONTENT (NS_FOCUS_EVENT_START + 1) + //@}