OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * This library is free software; you can redistribute it and/or | 4 * This library is free software; you can redistribute it and/or |
5 * modify it under the terms of the GNU Library General Public | 5 * modify it under the terms of the GNU Library General Public |
6 * License as published by the Free Software Foundation; either | 6 * License as published by the Free Software Foundation; either |
7 * version 2 of the License, or (at your option) any later version. | 7 * version 2 of the License, or (at your option) any later version. |
8 * | 8 * |
9 * This library is distributed in the hope that it will be useful, | 9 * This library is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 * Library General Public License for more details. | 12 * Library General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU Library General Public License | 14 * You should have received a copy of the GNU Library General Public License |
15 * along with this library; see the file COPYING.LIB. If not, write to | 15 * along with this library; see the file COPYING.LIB. If not, write to |
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 * Boston, MA 02110-1301, USA. | 17 * Boston, MA 02110-1301, USA. |
18 * | 18 * |
19 */ | 19 */ |
20 | 20 |
21 #include "core/html/forms/RadioButtonGroupScope.h" | 21 #include "core/html/forms/RadioButtonGroupScope.h" |
22 | 22 |
23 #include "core/InputTypeNames.h" | 23 #include "core/InputTypeNames.h" |
24 #include "core/html/HTMLInputElement.h" | 24 #include "core/html/HTMLInputElement.h" |
25 #include "wtf/HashSet.h" | 25 #include "wtf/HashMap.h" |
26 | 26 |
27 namespace blink { | 27 namespace blink { |
28 | 28 |
29 class RadioButtonGroup : public NoBaseWillBeGarbageCollected<RadioButtonGroup> { | 29 class RadioButtonGroup : public NoBaseWillBeGarbageCollected<RadioButtonGroup> { |
30 USING_FAST_MALLOC_WILL_BE_REMOVED(RadioButtonGroup); | 30 USING_FAST_MALLOC_WILL_BE_REMOVED(RadioButtonGroup); |
31 public: | 31 public: |
32 static PassOwnPtrWillBeRawPtr<RadioButtonGroup> create(); | 32 static PassOwnPtrWillBeRawPtr<RadioButtonGroup> create(); |
33 bool isEmpty() const { return m_members.isEmpty(); } | 33 bool isEmpty() const { return m_members.isEmpty(); } |
34 bool isRequired() const { return m_requiredCount; } | 34 bool isRequired() const { return m_requiredCount; } |
35 HTMLInputElement* checkedButton() const { return m_checkedButton; } | 35 HTMLInputElement* checkedButton() const { return m_checkedButton; } |
36 void add(HTMLInputElement*); | 36 void add(HTMLInputElement*); |
37 void updateCheckedState(HTMLInputElement*); | 37 void updateCheckedState(HTMLInputElement*); |
38 void requiredAttributeChanged(HTMLInputElement*); | 38 void requiredAttributeChanged(HTMLInputElement*); |
39 void remove(HTMLInputElement*); | 39 void remove(HTMLInputElement*); |
40 bool contains(HTMLInputElement*) const; | 40 bool contains(HTMLInputElement*) const; |
41 | 41 |
42 DECLARE_TRACE(); | 42 DECLARE_TRACE(); |
43 | 43 |
44 private: | 44 private: |
45 RadioButtonGroup(); | 45 RadioButtonGroup(); |
46 void setNeedsValidityCheckForAllButtons(); | 46 void setNeedsValidityCheckForAllButtons(); |
47 bool isValid() const; | 47 bool isValid() const; |
48 void setCheckedButton(HTMLInputElement*); | 48 void setCheckedButton(HTMLInputElement*); |
49 | 49 |
50 WillBeHeapHashSet<RawPtrWillBeMember<HTMLInputElement>> m_members; | 50 // The map records the 'required' state of each (button) element. |
| 51 using Members = WillBeHeapHashMap<RawPtrWillBeMember<HTMLInputElement>, bool
>; |
| 52 |
| 53 #if ENABLE(OILPAN) |
| 54 using MemberKeyValue = WTF::KeyValuePair<Member<HTMLInputElement>, bool>; |
| 55 #else |
| 56 using MemberKeyValue = WTF::KeyValuePair<HTMLInputElement*, bool>; |
| 57 #endif |
| 58 |
| 59 void updateRequiredButton(MemberKeyValue&, bool isRequired); |
| 60 |
| 61 Members m_members; |
51 RawPtrWillBeMember<HTMLInputElement> m_checkedButton; | 62 RawPtrWillBeMember<HTMLInputElement> m_checkedButton; |
52 size_t m_requiredCount; | 63 size_t m_requiredCount; |
53 }; | 64 }; |
54 | 65 |
55 RadioButtonGroup::RadioButtonGroup() | 66 RadioButtonGroup::RadioButtonGroup() |
56 : m_checkedButton(nullptr) | 67 : m_checkedButton(nullptr) |
57 , m_requiredCount(0) | 68 , m_requiredCount(0) |
58 { | 69 { |
59 } | 70 } |
60 | 71 |
(...skipping 10 matching lines...) Expand all Loading... |
71 void RadioButtonGroup::setCheckedButton(HTMLInputElement* button) | 82 void RadioButtonGroup::setCheckedButton(HTMLInputElement* button) |
72 { | 83 { |
73 HTMLInputElement* oldCheckedButton = m_checkedButton; | 84 HTMLInputElement* oldCheckedButton = m_checkedButton; |
74 if (oldCheckedButton == button) | 85 if (oldCheckedButton == button) |
75 return; | 86 return; |
76 m_checkedButton = button; | 87 m_checkedButton = button; |
77 if (oldCheckedButton) | 88 if (oldCheckedButton) |
78 oldCheckedButton->setChecked(false); | 89 oldCheckedButton->setChecked(false); |
79 } | 90 } |
80 | 91 |
| 92 void RadioButtonGroup::updateRequiredButton(MemberKeyValue& it, bool isRequired) |
| 93 { |
| 94 if (it.value == isRequired) |
| 95 return; |
| 96 |
| 97 it.value = isRequired; |
| 98 if (isRequired) { |
| 99 m_requiredCount++; |
| 100 } else { |
| 101 ASSERT(m_requiredCount); |
| 102 m_requiredCount--; |
| 103 } |
| 104 } |
| 105 |
81 void RadioButtonGroup::add(HTMLInputElement* button) | 106 void RadioButtonGroup::add(HTMLInputElement* button) |
82 { | 107 { |
83 ASSERT(button->type() == InputTypeNames::radio); | 108 ASSERT(button->type() == InputTypeNames::radio); |
84 if (!m_members.add(button).isNewEntry) | 109 auto addResult = m_members.add(button, false); |
| 110 if (!addResult.isNewEntry) |
85 return; | 111 return; |
86 bool groupWasValid = isValid(); | 112 bool groupWasValid = isValid(); |
87 if (button->isRequired()) | 113 updateRequiredButton(*addResult.storedValue, button->isRequired()); |
88 ++m_requiredCount; | |
89 if (button->checked()) | 114 if (button->checked()) |
90 setCheckedButton(button); | 115 setCheckedButton(button); |
91 | 116 |
92 bool groupIsValid = isValid(); | 117 bool groupIsValid = isValid(); |
93 if (groupWasValid != groupIsValid) { | 118 if (groupWasValid != groupIsValid) { |
94 setNeedsValidityCheckForAllButtons(); | 119 setNeedsValidityCheckForAllButtons(); |
95 } else if (!groupIsValid) { | 120 } else if (!groupIsValid) { |
96 // A radio button not in a group is always valid. We need to make it | 121 // A radio button not in a group is always valid. We need to make it |
97 // invalid only if the group is invalid. | 122 // invalid only if the group is invalid. |
98 button->setNeedsValidityCheck(); | 123 button->setNeedsValidityCheck(); |
99 } | 124 } |
100 } | 125 } |
101 | 126 |
102 void RadioButtonGroup::updateCheckedState(HTMLInputElement* button) | 127 void RadioButtonGroup::updateCheckedState(HTMLInputElement* button) |
103 { | 128 { |
104 ASSERT(button->type() == InputTypeNames::radio); | 129 ASSERT(button->type() == InputTypeNames::radio); |
105 ASSERT(m_members.contains(button)); | 130 ASSERT(m_members.contains(button)); |
106 bool wasValid = isValid(); | 131 bool wasValid = isValid(); |
107 if (button->checked()) { | 132 if (button->checked()) { |
108 setCheckedButton(button); | 133 setCheckedButton(button); |
109 } else { | 134 } else { |
110 if (m_checkedButton == button) | 135 if (m_checkedButton == button) |
111 m_checkedButton = nullptr; | 136 m_checkedButton = nullptr; |
112 } | 137 } |
113 if (wasValid != isValid()) | 138 if (wasValid != isValid()) |
114 setNeedsValidityCheckForAllButtons(); | 139 setNeedsValidityCheckForAllButtons(); |
115 for (HTMLInputElement* const inputElement : m_members) { | 140 for (auto& member : m_members) { |
| 141 HTMLInputElement* const inputElement = member.key; |
116 inputElement->pseudoStateChanged(CSSSelector::PseudoIndeterminate); | 142 inputElement->pseudoStateChanged(CSSSelector::PseudoIndeterminate); |
117 } | 143 } |
118 } | 144 } |
119 | 145 |
120 void RadioButtonGroup::requiredAttributeChanged(HTMLInputElement* button) | 146 void RadioButtonGroup::requiredAttributeChanged(HTMLInputElement* button) |
121 { | 147 { |
122 ASSERT(button->type() == InputTypeNames::radio); | 148 ASSERT(button->type() == InputTypeNames::radio); |
123 ASSERT(m_members.contains(button)); | 149 auto it = m_members.find(button); |
| 150 ASSERT(it != m_members.end()); |
124 bool wasValid = isValid(); | 151 bool wasValid = isValid(); |
125 if (button->isRequired()) { | 152 // Synchronize the 'required' flag for the button, along with |
126 ++m_requiredCount; | 153 // updating the overall count. |
127 } else { | 154 updateRequiredButton(*it, button->isRequired()); |
128 ASSERT(m_requiredCount); | |
129 --m_requiredCount; | |
130 } | |
131 if (wasValid != isValid()) | 155 if (wasValid != isValid()) |
132 setNeedsValidityCheckForAllButtons(); | 156 setNeedsValidityCheckForAllButtons(); |
133 } | 157 } |
134 | 158 |
135 void RadioButtonGroup::remove(HTMLInputElement* button) | 159 void RadioButtonGroup::remove(HTMLInputElement* button) |
136 { | 160 { |
137 ASSERT(button->type() == InputTypeNames::radio); | 161 ASSERT(button->type() == InputTypeNames::radio); |
138 WillBeHeapHashSet<RawPtrWillBeMember<HTMLInputElement>>::iterator it = m_mem
bers.find(button); | 162 auto it = m_members.find(button); |
139 if (it == m_members.end()) | 163 if (it == m_members.end()) |
140 return; | 164 return; |
141 bool wasValid = isValid(); | 165 bool wasValid = isValid(); |
| 166 ASSERT(it->value == button->isRequired()); |
| 167 updateRequiredButton(*it, false); |
142 m_members.remove(it); | 168 m_members.remove(it); |
143 if (button->isRequired()) { | |
144 ASSERT(m_requiredCount); | |
145 --m_requiredCount; | |
146 } | |
147 if (m_checkedButton == button) | 169 if (m_checkedButton == button) |
148 m_checkedButton = nullptr; | 170 m_checkedButton = nullptr; |
149 | 171 |
150 if (m_members.isEmpty()) { | 172 if (m_members.isEmpty()) { |
151 ASSERT(!m_requiredCount); | 173 ASSERT(!m_requiredCount); |
152 ASSERT(!m_checkedButton); | 174 ASSERT(!m_checkedButton); |
153 } else if (wasValid != isValid()) { | 175 } else if (wasValid != isValid()) { |
154 setNeedsValidityCheckForAllButtons(); | 176 setNeedsValidityCheckForAllButtons(); |
155 } | 177 } |
156 if (!wasValid) { | 178 if (!wasValid) { |
157 // A radio button not in a group is always valid. We need to make it | 179 // A radio button not in a group is always valid. We need to make it |
158 // valid only if the group was invalid. | 180 // valid only if the group was invalid. |
159 button->setNeedsValidityCheck(); | 181 button->setNeedsValidityCheck(); |
160 } | 182 } |
161 } | 183 } |
162 | 184 |
163 void RadioButtonGroup::setNeedsValidityCheckForAllButtons() | 185 void RadioButtonGroup::setNeedsValidityCheckForAllButtons() |
164 { | 186 { |
165 for (HTMLInputElement* const button : m_members) { | 187 for (auto& element : m_members) { |
| 188 HTMLInputElement* const button = element.key; |
166 ASSERT(button->type() == InputTypeNames::radio); | 189 ASSERT(button->type() == InputTypeNames::radio); |
167 button->setNeedsValidityCheck(); | 190 button->setNeedsValidityCheck(); |
168 } | 191 } |
169 } | 192 } |
170 | 193 |
171 bool RadioButtonGroup::contains(HTMLInputElement* button) const | 194 bool RadioButtonGroup::contains(HTMLInputElement* button) const |
172 { | 195 { |
173 return m_members.contains(button); | 196 return m_members.contains(button); |
174 } | 197 } |
175 | 198 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 } | 298 } |
276 | 299 |
277 DEFINE_TRACE(RadioButtonGroupScope) | 300 DEFINE_TRACE(RadioButtonGroupScope) |
278 { | 301 { |
279 #if ENABLE(OILPAN) | 302 #if ENABLE(OILPAN) |
280 visitor->trace(m_nameToGroupMap); | 303 visitor->trace(m_nameToGroupMap); |
281 #endif | 304 #endif |
282 } | 305 } |
283 | 306 |
284 } // namespace | 307 } // namespace |
OLD | NEW |