From ad4633017a5dfc666532fa6e009583fffdae3cbe Mon Sep 17 00:00:00 2001 From: Mounir Lamouri Date: Wed, 4 May 2011 14:45:47 +0200 Subject: [PATCH] Bug 641720 - Make nsHTMLInputElement::GetRadioGroupContainer saner. r=sicking,bz --- .../html/content/src/nsHTMLInputElement.cpp | 214 ++++++++---------- content/html/content/src/nsHTMLInputElement.h | 13 +- 2 files changed, 103 insertions(+), 124 deletions(-) diff --git a/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index bbc1f4523c9c..97355cc92c1b 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -909,12 +909,13 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, } if (mType == NS_FORM_INPUT_RADIO && aName == nsGkAtoms::required) { - nsCOMPtr c = GetRadioGroupContainer(); + nsIRadioGroupContainer* c = GetRadioGroupContainer(); nsCOMPtr container = do_QueryInterface(c); - nsAutoString name; - if (container && GetNameIfExists(name)) { + if (container) { + nsAutoString name; + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); container->RadioRequiredChanged(name, this); } } @@ -1576,12 +1577,11 @@ nsHTMLInputElement::DoSetChecked(PRBool aChecked, PRBool aNotify, if (aChecked) { rv = RadioSetChecked(aNotify); } else { - nsCOMPtr container = GetRadioGroupContainer(); + nsIRadioGroupContainer* container = GetRadioGroupContainer(); if (container) { nsAutoString name; - if (GetNameIfExists(name)) { - container->SetCurrentRadioButton(name, nsnull); - } + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); + container->SetCurrentRadioButton(name, nsnull); } // SetCheckedInternal is going to ask all radios to update their // validity state. We have to be sure the radio group container knows @@ -1618,9 +1618,10 @@ nsHTMLInputElement::RadioSetChecked(PRBool aNotify) // // Let the group know that we are now the One True Radio Button // - nsCOMPtr container = GetRadioGroupContainer(); - nsAutoString name; - if (container && GetNameIfExists(name)) { + nsIRadioGroupContainer* container = GetRadioGroupContainer(); + if (container) { + nsAutoString name; + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); rv = container->SetCurrentRadioButton(name, this); } @@ -1634,35 +1635,40 @@ nsHTMLInputElement::RadioSetChecked(PRBool aNotify) return rv; } -/* virtual */ already_AddRefed -nsHTMLInputElement::GetRadioGroupContainer() +nsIRadioGroupContainer* +nsHTMLInputElement::GetRadioGroupContainer() const { - nsIRadioGroupContainer* retval = nsnull; - if (mForm) { - CallQueryInterface(mForm, &retval); - } else { - nsIDocument* currentDoc = GetCurrentDoc(); - if (currentDoc) { - CallQueryInterface(currentDoc, &retval); - } + NS_ASSERTION(mType == NS_FORM_INPUT_RADIO, + "GetRadioGroupContainer should only be called when type='radio'"); + + nsAutoString name; + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); + + if (name.IsEmpty()) { + return nsnull; } - return retval; + + if (mForm) { + return mForm; + } + + nsIDocument* doc = GetCurrentDoc(); + nsCOMPtr group = do_QueryInterface(doc); + return group.get(); } already_AddRefed nsHTMLInputElement::GetSelectedRadioButton() { nsIDOMHTMLInputElement* selected; - nsCOMPtr container = GetRadioGroupContainer(); + nsIRadioGroupContainer* container = GetRadioGroupContainer(); if (!container) { return nsnull; } nsAutoString name; - if (!GetNameIfExists(name)) { - return nsnull; - } + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); container->GetCurrentRadioButton(name, &selected); return selected; @@ -2279,29 +2285,28 @@ nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) case NS_VK_DOWN: case NS_VK_RIGHT: // Arrow key pressed, focus+select prev/next radio button - nsCOMPtr container = GetRadioGroupContainer(); + nsIRadioGroupContainer* container = GetRadioGroupContainer(); if (container) { nsAutoString name; - if (GetNameIfExists(name)) { - nsCOMPtr selectedRadioButton; - container->GetNextRadioButton(name, isMovingBack, this, - getter_AddRefs(selectedRadioButton)); - nsCOMPtr radioContent = - do_QueryInterface(selectedRadioButton); - if (radioContent) { - rv = selectedRadioButton->Focus(); + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); + nsCOMPtr selectedRadioButton; + container->GetNextRadioButton(name, isMovingBack, this, + getter_AddRefs(selectedRadioButton)); + nsCOMPtr radioContent = + do_QueryInterface(selectedRadioButton); + if (radioContent) { + rv = selectedRadioButton->Focus(); + if (NS_SUCCEEDED(rv)) { + nsEventStatus status = nsEventStatus_eIgnore; + nsMouseEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), + NS_MOUSE_CLICK, nsnull, + nsMouseEvent::eReal); + event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_KEYBOARD; + rv = nsEventDispatcher::Dispatch(radioContent, + aVisitor.mPresContext, + &event, nsnull, &status); if (NS_SUCCEEDED(rv)) { - nsEventStatus status = nsEventStatus_eIgnore; - nsMouseEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), - NS_MOUSE_CLICK, nsnull, - nsMouseEvent::eReal); - event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_KEYBOARD; - rv = nsEventDispatcher::Dispatch(radioContent, - aVisitor.mPresContext, - &event, nsnull, &status); - if (NS_SUCCEEDED(rv)) { - aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; - } + aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } } @@ -3406,69 +3411,40 @@ nsHTMLInputElement::AddedToRadioGroup() nsCOMPtr container = GetRadioGroupContainer(); if (container) { nsAutoString name; - if (GetNameIfExists(name)) { - container->AddToRadioGroup(name, static_cast(this)); + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); + container->AddToRadioGroup(name, static_cast(this)); - // We initialize the validity of the element to the validity of the group - // because we assume UpdateValueMissingState() will be called after. - nsCOMPtr container2 = - do_QueryInterface(container); - SetValidityState(VALIDITY_STATE_VALUE_MISSING, - container2->GetValueMissingState(name)); - } + // We initialize the validity of the element to the validity of the group + // because we assume UpdateValueMissingState() will be called after. + nsCOMPtr container2 = + do_QueryInterface(container); + SetValidityState(VALIDITY_STATE_VALUE_MISSING, + container2->GetValueMissingState(name)); } } void nsHTMLInputElement::WillRemoveFromRadioGroup() { - // - // If the input element is not in a form and - // not in a document, we just need to return. - // - if (!mForm && !(IsInDoc() && GetParent())) { + nsIRadioGroupContainer* container = GetRadioGroupContainer(); + if (!container) { return; } - // + nsAutoString name; + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); + // If this button was checked, we need to notify the group that there is no // longer a selected radio button - // - nsAutoString name; - PRBool gotName = PR_FALSE; if (GetChecked()) { - if (!gotName) { - if (!GetNameIfExists(name)) { - // If the name doesn't exist, nothing is going to happen anyway - return; - } - gotName = PR_TRUE; - } - - nsCOMPtr container = GetRadioGroupContainer(); - if (container) { - container->SetCurrentRadioButton(name, nsnull); - } + container->SetCurrentRadioButton(name, nsnull); } - // - // Remove this radio from its group in the container - // - nsCOMPtr container = GetRadioGroupContainer(); - if (container) { - if (!gotName) { - if (!GetNameIfExists(name)) { - // If the name doesn't exist, nothing is going to happen anyway - return; - } - gotName = PR_TRUE; - } - - UpdateValueMissingValidityStateForRadio(true); - - container->RemoveFromRadioGroup(name, - static_cast(this)); - } + // Remove this radio from its group in the container. + // We need to call UpdateValueMissingValidityStateForRadio before to make sure + // the group validity is updated (with this element being ignored). + UpdateValueMissingValidityStateForRadio(true); + container->RemoveFromRadioGroup(name, static_cast(this)); } PRBool @@ -3529,13 +3505,15 @@ nsHTMLInputElement::IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRI // Current radio button is not selected. // But make it tabbable if nothing in group is selected. - nsCOMPtr container = GetRadioGroupContainer(); - nsAutoString name; - if (!container || !GetNameIfExists(name)) { + nsIRadioGroupContainer* container = GetRadioGroupContainer(); + if (!container) { *aIsFocusable = defaultFocusable; return PR_FALSE; } + nsAutoString name; + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); + nsCOMPtr currentRadio; container->GetCurrentRadioButton(name, getter_AddRefs(currentRadio)); if (currentRadio) { @@ -3548,19 +3526,15 @@ nsHTMLInputElement::IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRI nsresult nsHTMLInputElement::VisitGroup(nsIRadioVisitor* aVisitor, PRBool aFlushContent) { - nsresult rv = NS_OK; - nsCOMPtr container = GetRadioGroupContainer(); + nsIRadioGroupContainer* container = GetRadioGroupContainer(); if (container) { nsAutoString name; - if (GetNameIfExists(name)) { - rv = container->WalkRadioGroup(name, aVisitor, aFlushContent); - } else { - aVisitor->Visit(this); - } - } else { - aVisitor->Visit(this); + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); + return container->WalkRadioGroup(name, aVisitor, aFlushContent); } - return rv; + + aVisitor->Visit(this); + return NS_OK; } nsHTMLInputElement::ValueModeType @@ -3839,15 +3813,21 @@ nsHTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf) : HasAttr(kNameSpaceID_None, nsGkAtoms::required); bool valueMissing = false; - nsCOMPtr c = GetRadioGroupContainer(); + nsIRadioGroupContainer* c = GetRadioGroupContainer(); nsCOMPtr container = do_QueryInterface(c); + + if (!container) { + SetValidityState(VALIDITY_STATE_VALUE_MISSING, required && !selected); + return; + } + nsAutoString name; - GetNameIfExists(name); + GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); // If the current radio is required and not ignored, we can assume the entire // group is required. - if (!required && container && !name.IsEmpty()) { + if (!required) { required = (aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required)) ? container->GetRequiredRadioCount(name) - 1 : container->GetRequiredRadioCount(name); @@ -3855,18 +3835,14 @@ nsHTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf) valueMissing = required && !selected; - if (container && !name.IsEmpty()) { - if (container->GetValueMissingState(name) != valueMissing) { - container->SetValueMissingState(name, valueMissing); + if (container->GetValueMissingState(name) != valueMissing) { + container->SetValueMissingState(name, valueMissing); - SetValidityState(VALIDITY_STATE_VALUE_MISSING, valueMissing); - - nsCOMPtr visitor = - new nsRadioSetValueMissingState(this, valueMissing, notify); - VisitGroup(visitor, notify); - } - } else { SetValidityState(VALIDITY_STATE_VALUE_MISSING, valueMissing); + + nsCOMPtr visitor = + new nsRadioSetValueMissingState(this, valueMissing, notify); + VisitGroup(visitor, notify); } } diff --git a/content/html/content/src/nsHTMLInputElement.h b/content/html/content/src/nsHTMLInputElement.h index ac084f39bab3..1e4cb376b943 100644 --- a/content/html/content/src/nsHTMLInputElement.h +++ b/content/html/content/src/nsHTMLInputElement.h @@ -225,11 +225,6 @@ public: } void AddedToRadioGroup(); void WillRemoveFromRadioGroup(); - /** - * Get the radio group container for this button (form or document) - * @return the radio group container (or null if no form or document) - */ - virtual already_AddRefed GetRadioGroupContainer(); /** * Helper function returning the currently selected button in the radio group. @@ -577,6 +572,14 @@ protected: } } + /** + * Returns the radio group container if the element has one, null otherwise. + * The radio group container will be the form owner if there is one. + * The current document otherwise. + * @return the radio group container if the element has one, null otherwise. + */ + nsIRadioGroupContainer* GetRadioGroupContainer() const; + nsCOMPtr mControllers; /**