Bug 64702: Fix crash on focus by adding null checks, and make form.submit call onsubmit handlers before submitting. r=rods@netscape.com, sr=jst@netscape.com

This commit is contained in:
pollmann%netscape.com 2001-04-16 06:36:45 +00:00
Родитель 91932eae31
Коммит 3fe70eac5d
11 изменённых файлов: 102 добавлений и 284 удалений

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

@ -4062,6 +4062,23 @@ nsGenericHTMLLeafFormElement::SetAttribute(PRInt32 aNameSpaceID,
return SetFormControlAttribute(mForm, aNameSpaceID, aName, aValue, aNotify);
}
nsresult
nsGenericHTMLElement::SetElementFocus(PRBool aDoFocus)
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
if (!presContext) {
return NS_OK;
}
if (aDoFocus) {
return SetFocus(presContext);
}
return RemoveFocus(presContext);
}
nsresult
nsGenericHTMLElement::GetPluginInstance(nsIPluginInstance** aPluginInstance)
{

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

@ -348,6 +348,8 @@ public:
nsIHTMLAttributes* mAttributes;
protected:
nsresult SetElementFocus(PRBool aDoFocus);
nsresult GetPluginInstance(nsIPluginInstance** aPluginInstance);
nsresult GetPluginScriptObject(nsIScriptContext* aContext,

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

@ -260,47 +260,19 @@ nsHTMLAnchorElement::SetDocument(nsIDocument* aDocument, PRBool aDeep,
NS_IMETHODIMP
nsHTMLAnchorElement::Blur()
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
return RemoveFocus(presContext);
return SetElementFocus(PR_FALSE);
}
NS_IMETHODIMP
nsHTMLAnchorElement::Focus()
{
nsCOMPtr<nsIDocument> doc; // Strong
nsresult rv = GetDocument(*getter_AddRefs(doc));
if (NS_FAILED(rv)) { return rv; }
if (!doc) { return NS_ERROR_NULL_POINTER; }
PRInt32 numShells = doc->GetNumberOfShells();
nsCOMPtr<nsIPresContext> context;
for (PRInt32 i=0; i<numShells; i++) {
nsCOMPtr<nsIPresShell> shell = getter_AddRefs(doc->GetShellAt(i));
if (!shell) { return NS_ERROR_NULL_POINTER; }
rv = shell->GetPresContext(getter_AddRefs(context));
if (NS_FAILED(rv)) {
return rv;
}
if (!context) {
return NS_ERROR_NULL_POINTER;
}
rv = SetFocus(context);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
return SetElementFocus(PR_TRUE);
}
NS_IMETHODIMP
nsHTMLAnchorElement::SetFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// don't make the link grab the focus if there is no link handler
nsCOMPtr<nsILinkHandler> handler;
nsresult rv = aPresContext->GetLinkHandler(getter_AddRefs(handler));
@ -337,6 +309,7 @@ nsHTMLAnchorElement::SetFocus(nsIPresContext* aPresContext)
NS_IMETHODIMP
nsHTMLAnchorElement::RemoveFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// If we are disabled, we probably shouldn't have focus in the
// first place, so allow it to be removed.
nsresult rv = NS_OK;

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

@ -201,6 +201,7 @@ nsHTMLAreaElement::HandleDOMEvent(nsIPresContext* aPresContext,
NS_IMETHODIMP
nsHTMLAreaElement::SetFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
nsIEventStateManager* esm;
if (NS_OK == aPresContext->GetEventStateManager(&esm)) {
esm->SetContentState(this, NS_EVENT_STATE_FOCUS);
@ -212,6 +213,7 @@ nsHTMLAreaElement::SetFocus(nsIPresContext* aPresContext)
NS_IMETHODIMP
nsHTMLAreaElement::RemoveFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
nsIEventStateManager* esm;
if (NS_OK == aPresContext->GetEventStateManager(&esm)) {
esm->SetContentState(nsnull, NS_EVENT_STATE_FOCUS);

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

@ -238,22 +238,19 @@ NS_IMPL_STRING_ATTR(nsHTMLButtonElement, Value, value)
NS_IMETHODIMP
nsHTMLButtonElement::Blur()
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
return RemoveFocus(presContext);
return SetElementFocus(PR_FALSE);
}
NS_IMETHODIMP
nsHTMLButtonElement::Focus()
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
return SetFocus(presContext);
return SetElementFocus(PR_TRUE);
}
NS_IMETHODIMP
nsHTMLButtonElement::SetFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// first see if we are disabled or not. If disabled then do nothing.
nsAutoString disabled;
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(kNameSpaceID_HTML,
@ -279,6 +276,7 @@ nsHTMLButtonElement::SetFocus(nsIPresContext* aPresContext)
NS_IMETHODIMP
nsHTMLButtonElement::RemoveFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// If we are disabled, we probably shouldn't have focus in the
// first place, so allow it to be removed.
nsresult rv = NS_OK;

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

@ -326,76 +326,35 @@ NS_IMPL_STRING_ATTR(nsHTMLFormElement, Target, target)
NS_IMETHODIMP
nsHTMLFormElement::Submit()
{
// XXX Need to do something special with mailto: or news: URLs
nsCOMPtr<nsIDocument> doc;
nsresult res = GetDocument(*getter_AddRefs(doc));
if (NS_SUCCEEDED(res) && doc) {
// Make sure the presentation is up-to-date
doc->FlushPendingNotifications();
nsCOMPtr<nsIPresShell> shell = dont_AddRef(doc->GetShellAt(0));
if (shell) {
nsIFrame* frame;
shell->GetPrimaryFrameFor(this, &frame);
if (frame) {
nsIFormManager* formMan = nsnull; // weak reference, not refcounted
res = frame->QueryInterface(NS_GET_IID(nsIFormManager),
(void**)&formMan);
if (NS_SUCCEEDED(res) && formMan) {
nsCOMPtr<nsIPresContext> context;
shell->GetPresContext(getter_AddRefs(context));
if (context) {
// XXX We're currently passing in null for the frame.
// It works for now, but might not always
// be correct. In the future, we might not need the
// frame to be passed to the link handler.
res = formMan->OnSubmit(context, nsnull);
}
}
}
}
// Generate submit event
nsresult rv = NS_OK;
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
if (presContext) {
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_FORM_SUBMIT;
rv = HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
}
return res;
return rv;
}
NS_IMETHODIMP
nsHTMLFormElement::Reset()
{
nsCOMPtr<nsIDocument> doc;
nsresult res = GetDocument(*getter_AddRefs(doc));
if (NS_SUCCEEDED(res) && doc) {
PRInt32 numShells = doc->GetNumberOfShells();
nsCOMPtr<nsIPresContext> context;
for (PRInt32 i=0; i<numShells; i++) {
nsCOMPtr<nsIPresShell> shell = dont_AddRef(doc->GetShellAt(i));
if (shell) {
res = shell->GetPresContext(getter_AddRefs(context));
if (NS_SUCCEEDED(res) && context) {
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event;
event.eventStructType = NS_GUI_EVENT;
event.message = NS_FORM_RESET;
event.isShift = PR_FALSE;
event.isControl = PR_FALSE;
event.isAlt = PR_FALSE;
event.isMeta = PR_FALSE;
event.clickCount = 0;
event.widget = nsnull;
res = HandleDOMEvent(context, &event, nsnull, NS_EVENT_FLAG_INIT,
&status);
}
}
}
// Generate reset event
nsresult rv = NS_OK;
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
if (presContext) {
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_FORM_RESET;
rv = HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
}
return res;
return rv;
}
static nsGenericHTMLElement::EnumTable kFormMethodTable[] = {
@ -468,30 +427,34 @@ nsHTMLFormElement::HandleDOMEvent(nsIPresContext* aPresContext,
switch (aEvent->message) {
case NS_FORM_RESET:
case NS_FORM_SUBMIT:
{
// XXX Need to do something special with mailto: or news: URLs
nsIDocument* doc = nsnull; // Strong
nsresult res = GetDocument(doc);
if (NS_SUCCEEDED(res) && doc) {
// Make sure the presentation is up-to-date
doc->FlushPendingNotifications();
NS_RELEASE(doc);
}
// Make sure the presentation is up-to-date
nsCOMPtr<nsIDocument> doc;
GetDocument(*getter_AddRefs(doc));
if (doc) {
doc->FlushPendingNotifications();
}
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
if (shell) {
nsIFrame* frame;
shell->GetPrimaryFrameFor(this, &frame);
if (frame) {
nsIFormManager* formMan = nsnull;
ret = frame->QueryInterface(NS_GET_IID(nsIFormManager),
(void**)&formMan);
if (NS_SUCCEEDED(ret) && formMan) {
ret = formMan->OnReset(aPresContext);
}
}
}
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
if (shell) {
nsIFrame* frame;
shell->GetPrimaryFrameFor(this, &frame);
if (frame) {
nsIFormManager* formMan = nsnull;
ret = frame->QueryInterface(NS_GET_IID(nsIFormManager),
(void**)&formMan);
if (formMan) {
if (NS_FORM_RESET == aEvent->message) {
ret = formMan->OnReset(aPresContext);
}
else {
ret = formMan->OnSubmit(aPresContext, nsnull);
}
}
}
}
}
break;
}

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

@ -205,13 +205,6 @@ protected:
nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd);
nsresult MouseClickForAltText(nsIPresContext* aPresContext);
// If the PresShell is null then the PresContext will get its own and use it
nsresult DoManualSubmitOrReset(nsIPresContext* aPresContext,
nsIPresShell* aPresShell,
nsIFrame* aFormFrame,
nsIFrame* aFormControlFrame,
PRBool aDoSubmit, // Submit = TRUE, Reset = FALSE
PRBool aDoDOMEvent);
void SelectAll(nsIPresContext* aPresContext);
PRBool IsImage() const
@ -663,22 +656,19 @@ nsHTMLInputElement::SetChecked(PRBool aValue)
NS_IMETHODIMP
nsHTMLInputElement::Blur()
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
return RemoveFocus(presContext);
return SetElementFocus(PR_FALSE);
}
NS_IMETHODIMP
nsHTMLInputElement::Focus()
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
return SetFocus(presContext);
return SetElementFocus(PR_TRUE);
}
NS_IMETHODIMP
nsHTMLInputElement::SetFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// first see if we are disabled or not. If disabled then do nothing.
nsAutoString disabled;
if (NS_CONTENT_ATTR_HAS_VALUE ==
@ -713,6 +703,7 @@ nsHTMLInputElement::SetFocus(nsIPresContext* aPresContext)
NS_IMETHODIMP
nsHTMLInputElement::RemoveFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// If we are disabled, we probably shouldn't have focus in the
// first place, so allow it to be removed.
nsresult rv = NS_OK;
@ -877,104 +868,30 @@ nsHTMLInputElement::Click()
return NS_OK;
}
//////////////////////////////////////////////////////////////
// XXX - NOTE: This code is also in nsFormControlHelper and these two
// sections of code need to be in one place, but now that content and
// layout are in two different DLLs we need to think a little harder
// about how to do it
//
// manual submission helper method
// aPresShell - If the PresShell is null then the PresContext will
// get its own and use itstatic nsresult
// aFormFrame - The HTML Form's frame
// aFormControlFrame - The form controls frame that is calling this
// it can be null
// aDoSubmit - Submit = TRUE, Reset = FALSE
// Indicates whether to do DOM Processing of the event or to do regular frame processing
nsresult
nsHTMLInputElement::DoManualSubmitOrReset(nsIPresContext* aPresContext,
nsIPresShell* aPresShell,
nsIFrame* aFormFrame,
nsIFrame* aFormControlFrame,
PRBool aDoSubmit,
PRBool aDoDOMEvent)
{
NS_ENSURE_ARG_POINTER(aPresContext);
NS_ENSURE_ARG_POINTER(aFormFrame);
nsresult result = NS_OK;
nsCOMPtr<nsIContent> formContent;
aFormFrame->GetContent(getter_AddRefs(formContent));
nsEventStatus status = nsEventStatus_eIgnore;
if (formContent) {
//Either use the PresShell passed in or go get it from the PresContext
nsCOMPtr<nsIPresShell> shell; // this will do our clean up
if (aPresShell == nsnull) {
result = aPresContext->GetShell(getter_AddRefs(shell));
aPresShell = shell.get(); // not AddRefing because shell will clean up
}
// With a valid PreShell handle the event
if (NS_SUCCEEDED(result) && nsnull != aPresShell) {
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = aDoSubmit?NS_FORM_SUBMIT:NS_FORM_RESET;
if (aDoDOMEvent) {
aPresShell->HandleDOMEventWithTarget(formContent, &event, &status);
} else {
aPresShell->HandleEventWithTarget(&event, nsnull, formContent, NS_EVENT_FLAG_INIT, &status);
}
}
}
// Check status after handling event to make sure we should continue
if (nsEventStatus_eConsumeNoDefault != status) {
// get the form manager interface
nsIFormManager* formMan = nsnull; // weak reference, not refcounted
result = aFormFrame->QueryInterface(NS_GET_IID(nsIFormManager), (void**)&formMan);
if (NS_SUCCEEDED(result) && formMan) {
// now do the Submit or Reset
if (aDoSubmit) {
formMan->OnSubmit(aPresContext, aFormControlFrame);
} else {
formMan->OnReset(aPresContext);
}
}
}
return result;
}
nsresult
nsHTMLInputElement::MouseClickForAltText(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
PRBool disabled;
nsresult rv = GetDisabled(&disabled);
if (NS_FAILED(rv) || disabled) {
return rv;
}
// find form content & frame
nsIFrame* formFrame = nsnull;
nsCOMPtr<nsIContent> formContent(getter_AddRefs(nsGenericHTMLElement::FindFormParentContent(this)));
// Generate a submit event targetted at the form content
nsCOMPtr<nsIDOMHTMLFormElement> form;
GetForm(getter_AddRefs(form));
nsCOMPtr<nsIContent> formContent(do_QueryInterface(form));
if (formContent) {
nsCOMPtr<nsIDocument> doc;
nsresult res = GetDocument(*getter_AddRefs(doc));
if (NS_SUCCEEDED(res) && doc) {
// Make sure the presentation is up-to-date
doc->FlushPendingNotifications();
nsCOMPtr<nsIPresShell> shell = dont_AddRef(doc->GetShellAt(0));
if (shell) {
shell->GetPrimaryFrameFor(formContent, &formFrame);
}
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
if (shell) {
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_FORM_SUBMIT;
shell->HandleDOMEventWithTarget(formContent, &event, &status);
}
if (nsnull != formFrame) {
// NOTE: it is ok that the aFormControlFrame arg is NULL
// Do Submit & DOM Processing
DoManualSubmitOrReset(aPresContext, nsnull, formFrame, nsnull, PR_TRUE, PR_TRUE);
}
}
return rv;
}

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

@ -1021,26 +1021,19 @@ NS_IMPL_INT_ATTR(nsHTMLSelectElement, TabIndex, tabindex)
NS_IMETHODIMP
nsHTMLSelectElement::Blur()
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
return RemoveFocus(presContext);
return SetElementFocus(PR_FALSE);
}
NS_IMETHODIMP
nsHTMLSelectElement::Focus()
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
return SetFocus(presContext);
return SetElementFocus(PR_TRUE);
}
NS_IMETHODIMP
nsHTMLSelectElement::SetFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// first see if we are disabled or not. If disabled then do nothing.
nsAutoString disabled;
@ -1076,6 +1069,7 @@ nsHTMLSelectElement::SetFocus(nsIPresContext* aPresContext)
NS_IMETHODIMP
nsHTMLSelectElement::RemoveFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// If we are disabled, we probably shouldn't have focus in the
// first place, so allow it to be removed.
nsresult rv = NS_OK;

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

@ -192,26 +192,19 @@ nsHTMLTextAreaElement::GetForm(nsIDOMHTMLFormElement** aForm)
NS_IMETHODIMP
nsHTMLTextAreaElement::Blur()
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
return RemoveFocus(presContext);
return SetElementFocus(PR_FALSE);
}
NS_IMETHODIMP
nsHTMLTextAreaElement::Focus()
{
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(this, getter_AddRefs(presContext));
return SetFocus(presContext);
return SetElementFocus(PR_TRUE);
}
NS_IMETHODIMP
nsHTMLTextAreaElement::SetFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// first see if we are disabled or not. If disabled then do nothing.
nsAutoString disabled;
@ -243,6 +236,7 @@ nsHTMLTextAreaElement::SetFocus(nsIPresContext* aPresContext)
NS_IMETHODIMP
nsHTMLTextAreaElement::RemoveFocus(nsIPresContext* aPresContext)
{
NS_ENSURE_ARG_POINTER(aPresContext);
// If we are disabled, we probably shouldn't have focus in the
// first place, so allow it to be removed.
nsresult rv = NS_OK;

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

@ -992,27 +992,6 @@ nsFormControlHelper::DoManualSubmitOrReset(nsIPresContext* aPresContext,
}
}
}
// Check status after handling event to make sure we should continue
if (nsEventStatus_eConsumeNoDefault != status) {
// get the form manager interface
nsIFormManager* formMan = nsnull; // weak reference, not refcounted
result = aFormFrame->QueryInterface(NS_GET_IID(nsIFormManager), (void**)&formMan);
if (NS_SUCCEEDED(result) && formMan) {
// now do the Submit or Reset
if (aDoSubmit) {
// Now go back and get the frame for the control's content
// to make sure it is still valid
nsIFrame* controlFrame;
aPresShell->GetPrimaryFrameFor(controlContent, &controlFrame);
if (controlFrame != nsnull) {
formMan->OnSubmit(aPresContext, controlFrame);
}
} else {
formMan->OnReset(aPresContext);
}
}
}
return result;
}

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

@ -992,27 +992,6 @@ nsFormControlHelper::DoManualSubmitOrReset(nsIPresContext* aPresContext,
}
}
}
// Check status after handling event to make sure we should continue
if (nsEventStatus_eConsumeNoDefault != status) {
// get the form manager interface
nsIFormManager* formMan = nsnull; // weak reference, not refcounted
result = aFormFrame->QueryInterface(NS_GET_IID(nsIFormManager), (void**)&formMan);
if (NS_SUCCEEDED(result) && formMan) {
// now do the Submit or Reset
if (aDoSubmit) {
// Now go back and get the frame for the control's content
// to make sure it is still valid
nsIFrame* controlFrame;
aPresShell->GetPrimaryFrameFor(controlContent, &controlFrame);
if (controlFrame != nsnull) {
formMan->OnSubmit(aPresContext, controlFrame);
}
} else {
formMan->OnReset(aPresContext);
}
}
}
return result;
}