Index: Source/WebCore/dom/CheckedRadioButtons.cpp |
=================================================================== |
--- Source/WebCore/dom/CheckedRadioButtons.cpp (revision 111481) |
+++ Source/WebCore/dom/CheckedRadioButtons.cpp (working copy) |
@@ -22,244 +22,65 @@ |
#include "CheckedRadioButtons.h" |
#include "HTMLInputElement.h" |
-#include <wtf/HashSet.h> |
namespace WebCore { |
-class RadioButtonGroup { |
-public: |
- static PassOwnPtr<RadioButtonGroup> create(); |
- bool isEmpty() const { return m_members.isEmpty(); } |
- bool isRequired() const { return m_requiredCount; } |
- HTMLInputElement* checkedButton() const { return m_checkedButton; } |
- void add(HTMLInputElement*); |
- void updateCheckedState(HTMLInputElement*); |
- void requiredAttributeChanged(HTMLInputElement*); |
- void remove(HTMLInputElement*); |
- |
-private: |
- RadioButtonGroup(); |
- void setNeedsValidityCheckForAllButtons(); |
- bool isValid() const; |
- void setCheckedButton(HTMLInputElement*); |
- |
- HashSet<HTMLInputElement*> m_members; |
- HTMLInputElement* m_checkedButton; |
- size_t m_requiredCount; |
-}; |
- |
-RadioButtonGroup::RadioButtonGroup() |
- : m_checkedButton(0) |
- , m_requiredCount(0) |
-{ |
-} |
- |
-PassOwnPtr<RadioButtonGroup> RadioButtonGroup::create() |
-{ |
- return adoptPtr(new RadioButtonGroup); |
-} |
- |
-inline bool RadioButtonGroup::isValid() const |
-{ |
- return !isRequired() || m_checkedButton; |
-} |
- |
-void RadioButtonGroup::setCheckedButton(HTMLInputElement* button) |
-{ |
- HTMLInputElement* oldCheckedButton = m_checkedButton; |
- if (oldCheckedButton == button) |
- return; |
- m_checkedButton = button; |
- if (oldCheckedButton) |
- oldCheckedButton->setChecked(false); |
-} |
- |
-void RadioButtonGroup::add(HTMLInputElement* button) |
-{ |
- ASSERT(button->isRadioButton()); |
- if (!m_members.add(button).second) |
- return; |
- bool groupWasValid = isValid(); |
- if (button->required()) |
- ++m_requiredCount; |
- if (button->checked()) |
- setCheckedButton(button); |
- |
- bool groupIsValid = isValid(); |
- if (groupWasValid != groupIsValid) |
- setNeedsValidityCheckForAllButtons(); |
- else if (!groupIsValid) { |
- // A radio button not in a group is always valid. We need to make it |
- // invalid only if the group is invalid. |
- button->setNeedsValidityCheck(); |
- } |
-} |
- |
-void RadioButtonGroup::updateCheckedState(HTMLInputElement* button) |
-{ |
- ASSERT(button->isRadioButton()); |
- ASSERT(m_members.contains(button)); |
- bool wasValid = isValid(); |
- if (button->checked()) |
- setCheckedButton(button); |
- else { |
- if (m_checkedButton == button) |
- m_checkedButton = 0; |
- } |
- if (wasValid != isValid()) |
- setNeedsValidityCheckForAllButtons(); |
-} |
- |
-void RadioButtonGroup::requiredAttributeChanged(HTMLInputElement* button) |
-{ |
- ASSERT(button->isRadioButton()); |
- ASSERT(m_members.contains(button)); |
- bool wasValid = isValid(); |
- if (button->required()) |
- ++m_requiredCount; |
- else { |
- ASSERT(m_requiredCount); |
- --m_requiredCount; |
- } |
- if (wasValid != isValid()) |
- setNeedsValidityCheckForAllButtons(); |
-} |
- |
-void RadioButtonGroup::remove(HTMLInputElement* button) |
-{ |
- ASSERT(button->isRadioButton()); |
- HashSet<HTMLInputElement*>::iterator it = m_members.find(button); |
- if (it == m_members.end()) |
- return; |
- bool wasValid = isValid(); |
- m_members.remove(it); |
- if (button->required()) { |
- ASSERT(m_requiredCount); |
- --m_requiredCount; |
- } |
- if (m_checkedButton == button) |
- m_checkedButton = 0; |
- |
- if (m_members.isEmpty()) { |
- ASSERT(!m_requiredCount); |
- ASSERT(!m_checkedButton); |
- } else if (wasValid != isValid()) |
- setNeedsValidityCheckForAllButtons(); |
- if (!wasValid) { |
- // A radio button not in a group is always valid. We need to make it |
- // valid only if the group was invalid. |
- button->setNeedsValidityCheck(); |
- } |
-} |
- |
-void RadioButtonGroup::setNeedsValidityCheckForAllButtons() |
-{ |
- typedef HashSet<HTMLInputElement*>::const_iterator Iterator; |
- Iterator end = m_members.end(); |
- for (Iterator it = m_members.begin(); it != end; ++it) { |
- HTMLInputElement* button = *it; |
- ASSERT(button->isRadioButton()); |
- button->setNeedsValidityCheck(); |
- } |
-} |
- |
-// ---------------------------------------------------------------- |
- |
static inline bool shouldMakeRadioGroup(HTMLInputElement* element) |
{ |
return element->isRadioButton() && !element->name().isEmpty() && element->inDocument(); |
} |
-// Explicity define empty constructor and destructor in order to prevent the |
-// compiler from generating them as inlines. So we don't need to to define |
-// RadioButtonGroup in the header. |
-CheckedRadioButtons::CheckedRadioButtons() |
-{ |
-} |
- |
-CheckedRadioButtons::~CheckedRadioButtons() |
-{ |
-} |
- |
void CheckedRadioButtons::addButton(HTMLInputElement* element) |
{ |
if (!shouldMakeRadioGroup(element)) |
return; |
- if (!m_nameToGroupMap) |
- m_nameToGroupMap = adoptPtr(new NameToGroupMap); |
+ // We only track checked buttons. |
+ if (!element->checked()) |
+ return; |
- OwnPtr<RadioButtonGroup>& group = m_nameToGroupMap->add(element->name().impl(), PassOwnPtr<RadioButtonGroup>()).first->second; |
- if (!group) |
- group = RadioButtonGroup::create(); |
- group->add(element); |
-} |
+ if (!m_nameToCheckedRadioButtonMap) |
+ m_nameToCheckedRadioButtonMap = adoptPtr(new NameToInputMap); |
-void CheckedRadioButtons::updateCheckedState(HTMLInputElement* element) |
-{ |
- if (!shouldMakeRadioGroup(element)) |
+ pair<NameToInputMap::iterator, bool> result = m_nameToCheckedRadioButtonMap->add(element->name().impl(), element); |
+ if (result.second) |
return; |
- ASSERT(m_nameToGroupMap); |
- if (!m_nameToGroupMap) |
+ |
+ HTMLInputElement* oldCheckedButton = result.first->second; |
+ if (oldCheckedButton == element) |
return; |
- RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); |
- ASSERT(group); |
- group->updateCheckedState(element); |
-} |
-void CheckedRadioButtons::requiredAttributeChanged(HTMLInputElement* element) |
-{ |
- if (!shouldMakeRadioGroup(element)) |
- return; |
- ASSERT(m_nameToGroupMap); |
- if (!m_nameToGroupMap) |
- return; |
- RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); |
- ASSERT(group); |
- group->requiredAttributeChanged(element); |
+ result.first->second = element; |
+ oldCheckedButton->setChecked(false); |
} |
HTMLInputElement* CheckedRadioButtons::checkedButtonForGroup(const AtomicString& name) const |
{ |
- if (!m_nameToGroupMap) |
+ if (!m_nameToCheckedRadioButtonMap) |
return 0; |
- m_nameToGroupMap->checkConsistency(); |
- RadioButtonGroup* group = m_nameToGroupMap->get(name.impl()); |
- return group ? group->checkedButton() : 0; |
-} |
-bool CheckedRadioButtons::isInRequiredGroup(HTMLInputElement* element) const |
-{ |
- ASSERT(element->isRadioButton()); |
- if (!element->inDocument()) |
- return false; |
- if (!m_nameToGroupMap) |
- return false; |
- |
- RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); |
- return group && group->isRequired(); |
+ m_nameToCheckedRadioButtonMap->checkConsistency(); |
+ |
+ return m_nameToCheckedRadioButtonMap->get(name.impl()); |
} |
void CheckedRadioButtons::removeButton(HTMLInputElement* element) |
{ |
- if (!shouldMakeRadioGroup(element)) |
+ if (element->name().isEmpty() || !m_nameToCheckedRadioButtonMap) |
return; |
- if (!m_nameToGroupMap) |
+ |
+ m_nameToCheckedRadioButtonMap->checkConsistency(); |
+ |
+ NameToInputMap::iterator it = m_nameToCheckedRadioButtonMap->find(element->name().impl()); |
+ if (it == m_nameToCheckedRadioButtonMap->end() || it->second != element) |
return; |
+ |
+ ASSERT(element->shouldAppearChecked()); |
+ ASSERT(element->isRadioButton()); |
- m_nameToGroupMap->checkConsistency(); |
- NameToGroupMap::iterator it = m_nameToGroupMap->find(element->name().impl()); |
- if (it == m_nameToGroupMap->end()) |
- return; |
- it->second->remove(element); |
- if (it->second->isEmpty()) { |
- // FIXME: We may skip deallocating the empty RadioButtonGroup for |
- // performance improvement. If we do so, we need to change the key type |
- // of m_nameToGroupMap from AtomicStringImpl* to RefPtr<AtomicStringImpl>. |
- m_nameToGroupMap->remove(it); |
- if (m_nameToGroupMap->isEmpty()) |
- m_nameToGroupMap.clear(); |
- } |
+ m_nameToCheckedRadioButtonMap->remove(it); |
+ if (m_nameToCheckedRadioButtonMap->isEmpty()) |
+ m_nameToCheckedRadioButtonMap.clear(); |
} |
} // namespace |