Changeset 104668 in webkit
- Timestamp:
- Jan 10, 2012 9:03:23 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r104662 r104668 1 2012-01-04 Kent Tamura <tkent@chromium.org> 2 3 A radio button not in a Document should not join a radio button group 4 https://bugs.webkit.org/show_bug.cgi?id=45719 5 6 Reviewed by Darin Adler. 7 8 * fast/forms/radio/radio-group-expected.txt: Added. 9 * fast/forms/radio/radio-group.html: Added. 10 1 11 2012-01-10 João Paulo Rechi Vita <jprvita@openbossa.org> 2 12 -
trunk/Source/WebCore/ChangeLog
r104659 r104668 1 2012-01-04 Kent Tamura <tkent@chromium.org> 2 3 A radio button not in a document should not join a radio button group 4 https://bugs.webkit.org/show_bug.cgi?id=45719 5 6 Reviewed by Darin Adler. 7 8 As per the standard and other browser behaviors, we should not add a 9 radio button not in a document to a radio button group. 10 11 So, CheckedRadioButton member functions should be called in 12 insertedIntoDocument() and removedFromDocument(), and they should do 13 nothing if the specified radio button is not in a document. 14 15 This change also fixes a bug that form owner change by 'form' attribute 16 didn't update radio button groups correctly. 17 18 Test: fast/forms/radio/radio-group.html 19 20 * dom/CheckedRadioButtons.cpp: 21 (WebCore::shouldMakeRadioGroup): A helper function to check <input> state. 22 (WebCore::CheckedRadioButtons::addButton): 23 - Change the argument type: HTMLFormControlElement* -> HTMLInputElement*. 24 - Use shouldMakeRadioGroup(). 25 (WebCore::CheckedRadioButtons::removeButton): ditto. 26 * dom/CheckedRadioButtons.h: 27 Change the argument types of addButton() and removeButton(): 28 HTMLFormControlElement* -> HTMLInputElement*. 29 * html/FormAssociatedElement.cpp: 30 Do not update m_form except in setForm() and formWillBeDestroyed(). 31 This helps us to call registerFormElement() and removeFromElement() 32 correctly, and call willChangeForm()/didChangeForm() hooks correctly. 33 (WebCore::FormAssociatedElement::FormAssociatedElement): 34 (WebCore::FormAssociatedElement::~FormAssociatedElement): 35 (WebCore::FormAssociatedElement::insertedIntoTree): 36 (WebCore::FormAssociatedElement::removedFromTree): 37 (WebCore::FormAssociatedElement::setForm): 38 (WebCore::FormAssociatedElement::willChangeForm): 39 This virtual function is called before the owner form is updated. 40 (WebCore::FormAssociatedElement::didChangeForm): 41 This virtual function is called after the owner form was updated. 42 (WebCore::FormAssociatedElement::formWillBeDestroyed): 43 - Renamaed from formDestroyed() 44 - Add calls to willChangeForm() and didChangeForm(). 45 (WebCore::FormAssociatedElement::resetFormOwner): Use setForm(). 46 (WebCore::FormAssociatedElement::formAttributeChanged): ditto. 47 * html/FormAssociatedElement.h: 48 * html/HTMLFormControlElement.cpp: 49 (WebCore::HTMLFormControlElement::HTMLFormControlElement): Use setForm(). 50 (WebCore::HTMLFormControlElement::~HTMLFormControlElement): 51 removeFormElement() is not needed. ~FormAssociatedElement() treats it. 52 (WebCore::HTMLFormControlElement::parseMappedAttribute): 53 No need to handle CheckedRadioButtons here. It is handled by HTMLInputElement. 54 (WebCore::HTMLFormControlElement::insertedIntoTree): ditto. 55 * html/HTMLFormElement.cpp: 56 (WebCore::HTMLFormElement::~HTMLFormElement): 57 Rename formDestroyed() with willDestroyForm(). 58 (WebCore::HTMLFormElement::registerFormElement): 59 We don't need to handle radio button groups here. 60 (WebCore::HTMLFormElement::removeFormElement): ditto. 61 * html/HTMLInputElement.cpp: 62 (WebCore::HTMLInputElement::~HTMLInputElement): 63 Calls setForm(0) so that it calls correct virtual functions of 64 HTMLInputElement. 65 (WebCore::HTMLInputElement::updateCheckedRadioButtons): 66 Checking attached() was wrong. 67 (WebCore::HTMLInputElement::willChangeForm): 68 Remove this radio button from a radio button group for the old form. 69 (WebCore::HTMLInputElement::didChangeForm): 70 Add this radio button to a radio button group for the new form. 71 (WebCore::HTMLInputElement::insertedIntoDocument): 72 Add CheckedRadioButtons::addButton() call. 73 (WebCore::HTMLInputElement::removedFromDocument): 74 Add CheckedRadioButtons::removeButton() call. 75 (WebCore::HTMLInputElement::didMoveToNewDocument): 76 We don't need to handle CheckedRadioButton() here because 77 removedFromDocument() handles it. 78 * html/HTMLInputElement.h: 79 * html/HTMLObjectElement.cpp: 80 (WebCore::HTMLObjectElement::HTMLObjectElement): Use setForm(). 81 (WebCore::HTMLObjectElement::~HTMLObjectElement): 82 removeFormElement() is not needed. ~FormAssociatedElement() treats it. 83 1 84 2012-01-10 Kentaro Hara <haraken@chromium.org> 2 85 -
trunk/Source/WebCore/dom/CheckedRadioButtons.cpp
r94149 r104668 26 26 namespace WebCore { 27 27 28 void CheckedRadioButtons::addButton(HTMLFormControlElement* element)28 static inline bool shouldMakeRadioGroup(HTMLInputElement* element) 29 29 { 30 // We only want to add radio buttons. 31 if (!element->isRadioButton()) 30 return element->isRadioButton() && !element->name().isEmpty() && element->inDocument(); 31 } 32 33 void CheckedRadioButtons::addButton(HTMLInputElement* element) 34 { 35 if (!shouldMakeRadioGroup(element)) 32 36 return; 33 37 34 // Without a name, there is no group.35 if (element->name().isEmpty())36 return;37 38 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element);39 40 38 // We only track checked buttons. 41 if (! inputElement->checked())39 if (!element->checked()) 42 40 return; 43 41 … … 45 43 m_nameToCheckedRadioButtonMap = adoptPtr(new NameToInputMap); 46 44 47 pair<NameToInputMap::iterator, bool> result = m_nameToCheckedRadioButtonMap->add(element->name().impl(), inputElement);45 pair<NameToInputMap::iterator, bool> result = m_nameToCheckedRadioButtonMap->add(element->name().impl(), element); 48 46 if (result.second) 49 47 return; 50 48 51 49 HTMLInputElement* oldCheckedButton = result.first->second; 52 if (oldCheckedButton == inputElement)50 if (oldCheckedButton == element) 53 51 return; 54 52 55 result.first->second = inputElement;53 result.first->second = element; 56 54 oldCheckedButton->setChecked(false); 57 55 } … … 67 65 } 68 66 69 void CheckedRadioButtons::removeButton(HTML FormControlElement* element)67 void CheckedRadioButtons::removeButton(HTMLInputElement* element) 70 68 { 71 69 if (element->name().isEmpty() || !m_nameToCheckedRadioButtonMap) … … 78 76 return; 79 77 80 HTMLInputElement* inputElement = element->toInputElement(); 81 ASSERT_UNUSED(inputElement, inputElement); 82 ASSERT(inputElement->shouldAppearChecked()); 78 ASSERT(element->shouldAppearChecked()); 83 79 ASSERT(element->isRadioButton()); 84 80 -
trunk/Source/WebCore/dom/CheckedRadioButtons.h
r73430 r104668 28 28 namespace WebCore { 29 29 30 class HTMLFormControlElement;31 30 class HTMLInputElement; 32 31 33 32 class CheckedRadioButtons { 34 33 public: 35 void addButton(HTML FormControlElement*);36 void removeButton(HTML FormControlElement*);34 void addButton(HTMLInputElement*); 35 void removeButton(HTMLInputElement*); 37 36 HTMLInputElement* checkedButtonForGroup(const AtomicString& groupName) const; 38 37 -
trunk/Source/WebCore/html/FormAssociatedElement.cpp
r103679 r104668 36 36 using namespace HTMLNames; 37 37 38 FormAssociatedElement::FormAssociatedElement( HTMLFormElement* form)39 : m_form( form)38 FormAssociatedElement::FormAssociatedElement() 39 : m_form(0) 40 40 { 41 41 } … … 43 43 FormAssociatedElement::~FormAssociatedElement() 44 44 { 45 setForm(0); 45 46 } 46 47 … … 77 78 { 78 79 HTMLElement* element = toHTMLElement(this); 79 if (element->fastHasAttribute(formAttr)) { 80 // Resets the form owner at first to make sure the element don't 81 // associate any form elements when there is no element which has 82 // the given ID. 83 if (m_form) { 84 m_form->removeFormElement(this); 85 m_form = 0; 86 } 87 Element* formElement = element->treeScope()->getElementById(element->fastGetAttribute(formAttr)); 88 if (formElement && formElement->hasTagName(formTag)) { 89 m_form = static_cast<HTMLFormElement*>(formElement); 90 m_form->registerFormElement(this); 91 } 80 const AtomicString& formId = element->fastGetAttribute(formAttr); 81 if (!formId.isNull()) { 82 HTMLFormElement* newForm = 0; 83 Element* newFormCandidate = element->treeScope()->getElementById(formId); 84 if (newFormCandidate && newFormCandidate->hasTagName(formTag)) 85 newForm = static_cast<HTMLFormElement*>(newFormCandidate); 86 setForm(newForm); 92 87 return; 93 88 } … … 97 92 // setting a form, we will already have a non-null value for m_form, 98 93 // and so we don't need to do anything. 99 m_form = element->findFormAncestor(); 100 if (m_form) 101 m_form->registerFormElement(this); 94 setForm(element->findFormAncestor()); 102 95 } 103 96 } … … 118 111 // Otherwise, null out our form and remove ourselves from the form's list of elements. 119 112 if (m_form && findRoot(element) != findRoot(m_form)) 120 removeFromForm();113 setForm(0); 121 114 } 122 115 123 void FormAssociatedElement:: removeFromForm()116 void FormAssociatedElement::setForm(HTMLFormElement* newForm) 124 117 { 118 if (m_form == newForm) 119 return; 120 willChangeForm(); 121 if (m_form) 122 m_form->removeFormElement(this); 123 m_form = newForm; 124 if (m_form) 125 m_form->registerFormElement(this); 126 didChangeForm(); 127 } 128 129 void FormAssociatedElement::willChangeForm() 130 { 131 } 132 133 void FormAssociatedElement::didChangeForm() 134 { 135 } 136 137 void FormAssociatedElement::formWillBeDestroyed() 138 { 139 ASSERT(m_form); 125 140 if (!m_form) 126 141 return; 127 m_form->removeFormElement(this);142 willChangeForm(); 128 143 m_form = 0; 144 didChangeForm(); 129 145 } 130 146 … … 136 152 if (formId.isNull()) 137 153 return; 138 m_form->removeFormElement(this);139 154 } 140 m_form = 0;155 HTMLFormElement* newForm = 0; 141 156 if (!formId.isNull() && element->inDocument()) { 142 157 // The HTML5 spec says that the element should be associated with … … 146 161 Element* firstElement = element->treeScope()->getElementById(formId); 147 162 if (firstElement && firstElement->hasTagName(formTag)) 148 m_form = static_cast<HTMLFormElement*>(firstElement);163 newForm = static_cast<HTMLFormElement*>(firstElement); 149 164 } else 150 m_form = element->findFormAncestor(); 151 if (m_form) 152 m_form->registerFormElement(this); 165 newForm = element->findFormAncestor(); 166 setForm(newForm); 153 167 } 154 168 … … 158 172 if (!element->fastHasAttribute(formAttr)) { 159 173 // The form attribute removed. We need to reset form owner here. 160 if (m_form) 161 m_form->removeFormElement(this); 162 m_form = element->findFormAncestor(); 163 if (m_form) 164 form()->registerFormElement(this); 174 setForm(element->findFormAncestor()); 165 175 element->document()->unregisterFormElementWithFormAttribute(this); 166 176 } else -
trunk/Source/WebCore/html/FormAssociatedElement.h
r103679 r104668 54 54 virtual bool appendFormData(FormDataList&, bool) { return false; } 55 55 56 v irtual void formDestroyed() { m_form = 0; }56 void formWillBeDestroyed(); 57 57 58 58 void resetFormOwner(); 59 59 60 60 protected: 61 FormAssociatedElement( HTMLFormElement*);61 FormAssociatedElement(); 62 62 63 63 void insertedIntoTree(); … … 67 67 void didMoveToNewDocument(Document* oldDocument); 68 68 69 void setForm(HTMLFormElement* form) { m_form = form; } 70 void removeFromForm(); 69 void setForm(HTMLFormElement*); 71 70 void formAttributeChanged(); 71 72 // If you add an override of willChangeForm() or didChangeForm() to a class 73 // derived from this one, you will need to add a call to setForm(0) to the 74 // destructor of that class. 75 virtual void willChangeForm(); 76 virtual void didChangeForm(); 72 77 73 78 private: -
trunk/Source/WebCore/html/HTMLFormControlElement.cpp
r104274 r104668 51 51 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form) 52 52 : HTMLElement(tagName, document) 53 , FormAssociatedElement(form)54 53 , m_disabled(false) 55 54 , m_readOnly(false) … … 62 61 , m_hasAutofocused(false) 63 62 { 64 if (!this->form()) 65 setForm(findFormAncestor()); 66 if (this->form()) 67 this->form()->registerFormElement(this); 68 63 setForm(form ? form : findFormAncestor()); 69 64 setHasCustomWillOrDidRecalcStyle(); 70 65 } … … 72 67 HTMLFormControlElement::~HTMLFormControlElement() 73 68 { 74 if (form())75 form()->removeFormElement(this);76 69 } 77 70 … … 109 102 void HTMLFormControlElement::parseMappedAttribute(Attribute* attr) 110 103 { 111 if (attr->name() == formAttr) {104 if (attr->name() == formAttr) 112 105 formAttributeChanged(); 113 if (!form()) 114 document()->checkedRadioButtons().addButton(this); 115 } else if (attr->name() == disabledAttr) { 106 else if (attr->name() == disabledAttr) { 116 107 bool oldDisabled = m_disabled; 117 108 m_disabled = !attr->isNull(); … … 206 197 { 207 198 FormAssociatedElement::insertedIntoTree(); 208 if (!form())209 document()->checkedRadioButtons().addButton(this);210 211 199 HTMLElement::insertedIntoTree(deep); 212 200 } -
trunk/Source/WebCore/html/HTMLFormElement.cpp
r104383 r104668 96 96 97 97 for (unsigned i = 0; i < m_associatedElements.size(); ++i) 98 m_associatedElements[i]->form Destroyed();98 m_associatedElements[i]->formWillBeDestroyed(); 99 99 for (unsigned i = 0; i < m_imageElements.size(); ++i) 100 100 m_imageElements[i]->m_form = 0; … … 457 457 void HTMLFormElement::registerFormElement(FormAssociatedElement* e) 458 458 { 459 if (e->isFormControlElement()) {460 HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(e);461 document()->checkedRadioButtons().removeButton(element);462 m_checkedRadioButtons.addButton(element);463 }464 459 m_associatedElements.insert(formElementIndex(e), e); 465 460 } … … 467 462 void HTMLFormElement::removeFormElement(FormAssociatedElement* e) 468 463 { 469 if (e->isFormControlElement())470 m_checkedRadioButtons.removeButton(static_cast<HTMLFormControlElement*>(e));471 464 unsigned index; 472 465 for (index = 0; index < m_associatedElements.size(); ++index) { -
trunk/Source/WebCore/html/HTMLInputElement.cpp
r104383 r104668 117 117 document()->unregisterForPageCacheSuspensionCallbacks(this); 118 118 119 document()->checkedRadioButtons().removeButton(this); 120 121 // Need to remove this from the form while it is still an HTMLInputElement, 122 // so can't wait for the base class's destructor to do it. 123 removeFromForm(); 119 // Need to remove form association while this is still an HTMLInputElement 120 // so that virtual functions are called correctly. 121 setForm(0); 124 122 } 125 123 … … 180 178 void HTMLInputElement::updateCheckedRadioButtons() 181 179 { 182 if (attached() && checked()) 183 checkedRadioButtons().addButton(this); 180 checkedRadioButtons().addButton(this); 184 181 185 182 if (form()) { … … 1503 1500 } 1504 1501 1502 void HTMLInputElement::willChangeForm() 1503 { 1504 checkedRadioButtons().removeButton(this); 1505 HTMLTextFormControlElement::willChangeForm(); 1506 } 1507 1508 void HTMLInputElement::didChangeForm() 1509 { 1510 HTMLTextFormControlElement::didChangeForm(); 1511 checkedRadioButtons().addButton(this); 1512 } 1513 1514 void HTMLInputElement::insertedIntoDocument() 1515 { 1516 HTMLTextFormControlElement::insertedIntoDocument(); 1517 ASSERT(inDocument()); 1518 checkedRadioButtons().addButton(this); 1519 } 1520 1521 void HTMLInputElement::removedFromDocument() 1522 { 1523 ASSERT(inDocument()); 1524 checkedRadioButtons().removeButton(this); 1525 HTMLTextFormControlElement::removedFromDocument(); 1526 } 1527 1505 1528 void HTMLInputElement::didMoveToNewDocument(Document* oldDocument) 1506 1529 { -
trunk/Source/WebCore/html/HTMLInputElement.h
r103679 r104668 250 250 enum AnyStepHandling { RejectAny, AnyIsDefaultStep }; 251 251 252 virtual void willChangeForm() OVERRIDE; 253 virtual void didChangeForm() OVERRIDE; 254 virtual void insertedIntoDocument() OVERRIDE; 255 virtual void removedFromDocument() OVERRIDE; 252 256 virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE; 253 257 -
trunk/Source/WebCore/html/HTMLObjectElement.cpp
r103679 r104668 56 56 inline HTMLObjectElement::HTMLObjectElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser) 57 57 : HTMLPlugInImageElement(tagName, document, createdByParser, ShouldNotPreferPlugInsForImages) 58 , FormAssociatedElement(form)59 58 , m_docNamedItem(true) 60 59 , m_useFallbackContent(false) 61 60 { 62 61 ASSERT(hasTagName(objectTag)); 63 if (!this->form()) 64 setForm(findFormAncestor()); 65 if (this->form()) 66 this->form()->registerFormElement(this); 62 setForm(form ? form : findFormAncestor()); 67 63 } 68 64 69 65 inline HTMLObjectElement::~HTMLObjectElement() 70 66 { 71 if (form())72 form()->removeFormElement(this);73 67 } 74 68
Note: See TracChangeset
for help on using the changeset viewer.