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 |
(...skipping 14 matching lines...) Expand all Loading... |
25 #include <wtf/HashSet.h> | 25 #include <wtf/HashSet.h> |
26 | 26 |
27 namespace WebCore { | 27 namespace WebCore { |
28 | 28 |
29 class RadioButtonGroup { | 29 class RadioButtonGroup { |
30 WTF_MAKE_FAST_ALLOCATED; | 30 WTF_MAKE_FAST_ALLOCATED; |
31 public: | 31 public: |
32 static PassOwnPtr<RadioButtonGroup> create(); | 32 static PassOwnPtr<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 Result<HTMLInputElement> checkedButton() const { return Handle<HTMLInputElem
ent>(m_checkedButton); } // FIXME(oilpan): Remove Handle<>(). |
36 void add(HTMLInputElement*); | 36 void add(Handle<HTMLInputElement>); |
37 void updateCheckedState(HTMLInputElement*); | 37 void updateCheckedState(Handle<HTMLInputElement>); |
38 void requiredAttributeChanged(HTMLInputElement*); | 38 void requiredAttributeChanged(Handle<HTMLInputElement>); |
39 void remove(HTMLInputElement*); | 39 void remove(Handle<HTMLInputElement>); |
40 bool contains(HTMLInputElement*) const; | 40 bool contains(Handle<HTMLInputElement>) const; |
41 | 41 |
42 private: | 42 private: |
43 RadioButtonGroup(); | 43 RadioButtonGroup(); |
44 void setNeedsValidityCheckForAllButtons(); | 44 void setNeedsValidityCheckForAllButtons(); |
45 bool isValid() const; | 45 bool isValid() const; |
46 void setCheckedButton(HTMLInputElement*); | 46 void setCheckedButton(Handle<HTMLInputElement>); |
47 | 47 |
| 48 // FIXME(oilpan): Move RadioButtonGroup to the heap and use Members. |
48 HashSet<HTMLInputElement*> m_members; | 49 HashSet<HTMLInputElement*> m_members; |
49 HTMLInputElement* m_checkedButton; | 50 HTMLInputElement* m_checkedButton; |
50 size_t m_requiredCount; | 51 size_t m_requiredCount; |
51 }; | 52 }; |
52 | 53 |
53 RadioButtonGroup::RadioButtonGroup() | 54 RadioButtonGroup::RadioButtonGroup() |
54 : m_checkedButton(0) | 55 : m_checkedButton(0) |
55 , m_requiredCount(0) | 56 , m_requiredCount(0) |
56 { | 57 { |
57 } | 58 } |
58 | 59 |
59 PassOwnPtr<RadioButtonGroup> RadioButtonGroup::create() | 60 PassOwnPtr<RadioButtonGroup> RadioButtonGroup::create() |
60 { | 61 { |
61 return adoptPtr(new RadioButtonGroup); | 62 return adoptPtr(new RadioButtonGroup); |
62 } | 63 } |
63 | 64 |
64 inline bool RadioButtonGroup::isValid() const | 65 inline bool RadioButtonGroup::isValid() const |
65 { | 66 { |
66 return !isRequired() || m_checkedButton; | 67 return !isRequired() || m_checkedButton; |
67 } | 68 } |
68 | 69 |
69 void RadioButtonGroup::setCheckedButton(HTMLInputElement* button) | 70 void RadioButtonGroup::setCheckedButton(Handle<HTMLInputElement> button) |
70 { | 71 { |
71 HTMLInputElement* oldCheckedButton = m_checkedButton; | 72 Handle<HTMLInputElement> oldCheckedButton = Handle<HTMLInputElement>(m_check
edButton); // FIXME(oilpan): Remove Handle<>(). |
72 if (oldCheckedButton == button) | 73 if (oldCheckedButton == button) |
73 return; | 74 return; |
74 m_checkedButton = button; | 75 m_checkedButton = button.raw(); |
75 if (oldCheckedButton) | 76 if (oldCheckedButton) |
76 oldCheckedButton->setChecked(false); | 77 oldCheckedButton->setChecked(false); |
77 } | 78 } |
78 | 79 |
79 void RadioButtonGroup::add(HTMLInputElement* button) | 80 void RadioButtonGroup::add(Handle<HTMLInputElement> button) |
80 { | 81 { |
81 ASSERT(button->isRadioButton()); | 82 ASSERT(button->isRadioButton()); |
82 if (!m_members.add(button).isNewEntry) | 83 if (!m_members.add(button.raw()).isNewEntry) |
83 return; | 84 return; |
84 bool groupWasValid = isValid(); | 85 bool groupWasValid = isValid(); |
85 if (button->isRequired()) | 86 if (button->isRequired()) |
86 ++m_requiredCount; | 87 ++m_requiredCount; |
87 if (button->checked()) | 88 if (button->checked()) |
88 setCheckedButton(button); | 89 setCheckedButton(button); |
89 | 90 |
90 bool groupIsValid = isValid(); | 91 bool groupIsValid = isValid(); |
91 if (groupWasValid != groupIsValid) | 92 if (groupWasValid != groupIsValid) |
92 setNeedsValidityCheckForAllButtons(); | 93 setNeedsValidityCheckForAllButtons(); |
93 else if (!groupIsValid) { | 94 else if (!groupIsValid) { |
94 // A radio button not in a group is always valid. We need to make it | 95 // A radio button not in a group is always valid. We need to make it |
95 // invalid only if the group is invalid. | 96 // invalid only if the group is invalid. |
96 button->setNeedsValidityCheck(); | 97 button->setNeedsValidityCheck(); |
97 } | 98 } |
98 } | 99 } |
99 | 100 |
100 void RadioButtonGroup::updateCheckedState(HTMLInputElement* button) | 101 void RadioButtonGroup::updateCheckedState(Handle<HTMLInputElement> button) |
101 { | 102 { |
102 ASSERT(button->isRadioButton()); | 103 ASSERT(button->isRadioButton()); |
103 ASSERT(m_members.contains(button)); | 104 ASSERT(m_members.contains(button.raw())); |
104 bool wasValid = isValid(); | 105 bool wasValid = isValid(); |
105 if (button->checked()) | 106 if (button->checked()) |
106 setCheckedButton(button); | 107 setCheckedButton(button); |
107 else { | 108 else { |
108 if (m_checkedButton == button) | 109 if (m_checkedButton == button.raw()) |
109 m_checkedButton = 0; | 110 m_checkedButton = 0; |
110 } | 111 } |
111 if (wasValid != isValid()) | 112 if (wasValid != isValid()) |
112 setNeedsValidityCheckForAllButtons(); | 113 setNeedsValidityCheckForAllButtons(); |
113 } | 114 } |
114 | 115 |
115 void RadioButtonGroup::requiredAttributeChanged(HTMLInputElement* button) | 116 void RadioButtonGroup::requiredAttributeChanged(Handle<HTMLInputElement> button) |
116 { | 117 { |
117 ASSERT(button->isRadioButton()); | 118 ASSERT(button->isRadioButton()); |
118 ASSERT(m_members.contains(button)); | 119 ASSERT(m_members.contains(button.raw())); |
119 bool wasValid = isValid(); | 120 bool wasValid = isValid(); |
120 if (button->isRequired()) | 121 if (button->isRequired()) |
121 ++m_requiredCount; | 122 ++m_requiredCount; |
122 else { | 123 else { |
123 ASSERT(m_requiredCount); | 124 ASSERT(m_requiredCount); |
124 --m_requiredCount; | 125 --m_requiredCount; |
125 } | 126 } |
126 if (wasValid != isValid()) | 127 if (wasValid != isValid()) |
127 setNeedsValidityCheckForAllButtons(); | 128 setNeedsValidityCheckForAllButtons(); |
128 } | 129 } |
129 | 130 |
130 void RadioButtonGroup::remove(HTMLInputElement* button) | 131 void RadioButtonGroup::remove(Handle<HTMLInputElement> button) |
131 { | 132 { |
132 ASSERT(button->isRadioButton()); | 133 ASSERT(button->isRadioButton()); |
133 HashSet<HTMLInputElement*>::iterator it = m_members.find(button); | 134 HashSet<HTMLInputElement*>::iterator it = m_members.find(button.raw()); |
134 if (it == m_members.end()) | 135 if (it == m_members.end()) |
135 return; | 136 return; |
136 bool wasValid = isValid(); | 137 bool wasValid = isValid(); |
137 m_members.remove(it); | 138 m_members.remove(it); |
138 if (button->isRequired()) { | 139 if (button->isRequired()) { |
139 ASSERT(m_requiredCount); | 140 ASSERT(m_requiredCount); |
140 --m_requiredCount; | 141 --m_requiredCount; |
141 } | 142 } |
142 if (m_checkedButton == button) | 143 if (m_checkedButton == button.raw()) |
143 m_checkedButton = 0; | 144 m_checkedButton = 0; |
144 | 145 |
145 if (m_members.isEmpty()) { | 146 if (m_members.isEmpty()) { |
146 ASSERT(!m_requiredCount); | 147 ASSERT(!m_requiredCount); |
147 ASSERT(!m_checkedButton); | 148 ASSERT(!m_checkedButton); |
148 } else if (wasValid != isValid()) | 149 } else if (wasValid != isValid()) |
149 setNeedsValidityCheckForAllButtons(); | 150 setNeedsValidityCheckForAllButtons(); |
150 if (!wasValid) { | 151 if (!wasValid) { |
151 // A radio button not in a group is always valid. We need to make it | 152 // A radio button not in a group is always valid. We need to make it |
152 // valid only if the group was invalid. | 153 // valid only if the group was invalid. |
153 button->setNeedsValidityCheck(); | 154 button->setNeedsValidityCheck(); |
154 } | 155 } |
155 } | 156 } |
156 | 157 |
157 void RadioButtonGroup::setNeedsValidityCheckForAllButtons() | 158 void RadioButtonGroup::setNeedsValidityCheckForAllButtons() |
158 { | 159 { |
159 typedef HashSet<HTMLInputElement*>::const_iterator Iterator; | 160 typedef HashSet<HTMLInputElement*>::const_iterator Iterator; |
160 Iterator end = m_members.end(); | 161 Iterator end = m_members.end(); |
161 for (Iterator it = m_members.begin(); it != end; ++it) { | 162 for (Iterator it = m_members.begin(); it != end; ++it) { |
162 HTMLInputElement* button = *it; | 163 Handle<HTMLInputElement> button = Handle<HTMLInputElement>(*it); // FIXM
E(oilpan): Remove Handle<>(). |
163 ASSERT(button->isRadioButton()); | 164 ASSERT(button->isRadioButton()); |
164 button->setNeedsValidityCheck(); | 165 button->setNeedsValidityCheck(); |
165 } | 166 } |
166 } | 167 } |
167 | 168 |
168 bool RadioButtonGroup::contains(HTMLInputElement* button) const | 169 bool RadioButtonGroup::contains(Handle<HTMLInputElement> button) const |
169 { | 170 { |
170 return m_members.contains(button); | 171 return m_members.contains(button.raw()); |
171 } | 172 } |
172 | 173 |
173 // ---------------------------------------------------------------- | 174 // ---------------------------------------------------------------- |
174 | 175 |
175 // Explicity define empty constructor and destructor in order to prevent the | 176 // Explicity define empty constructor and destructor in order to prevent the |
176 // compiler from generating them as inlines. So we don't need to to define | 177 // compiler from generating them as inlines. So we don't need to to define |
177 // RadioButtonGroup in the header. | 178 // RadioButtonGroup in the header. |
178 CheckedRadioButtons::CheckedRadioButtons() | 179 CheckedRadioButtons::CheckedRadioButtons() |
179 { | 180 { |
180 } | 181 } |
181 | 182 |
182 CheckedRadioButtons::~CheckedRadioButtons() | 183 CheckedRadioButtons::~CheckedRadioButtons() |
183 { | 184 { |
184 } | 185 } |
185 | 186 |
186 void CheckedRadioButtons::addButton(HTMLInputElement* element) | 187 void CheckedRadioButtons::addButton(Handle<HTMLInputElement> element) |
187 { | 188 { |
188 ASSERT(element->isRadioButton()); | 189 ASSERT(element->isRadioButton()); |
189 if (element->name().isEmpty()) | 190 if (element->name().isEmpty()) |
190 return; | 191 return; |
191 | 192 |
192 if (!m_nameToGroupMap) | 193 if (!m_nameToGroupMap) |
193 m_nameToGroupMap = adoptPtr(new NameToGroupMap); | 194 m_nameToGroupMap = adoptPtr(new NameToGroupMap); |
194 | 195 |
195 OwnPtr<RadioButtonGroup>& group = m_nameToGroupMap->add(element->name().impl
(), PassOwnPtr<RadioButtonGroup>()).iterator->value; | 196 OwnPtr<RadioButtonGroup>& group = m_nameToGroupMap->add(element->name().impl
(), PassOwnPtr<RadioButtonGroup>()).iterator->value; |
196 if (!group) | 197 if (!group) |
197 group = RadioButtonGroup::create(); | 198 group = RadioButtonGroup::create(); |
198 group->add(element); | 199 group->add(element); |
199 } | 200 } |
200 | 201 |
201 void CheckedRadioButtons::updateCheckedState(HTMLInputElement* element) | 202 void CheckedRadioButtons::updateCheckedState(Handle<HTMLInputElement> element) |
202 { | 203 { |
203 ASSERT(element->isRadioButton()); | 204 ASSERT(element->isRadioButton()); |
204 if (element->name().isEmpty()) | 205 if (element->name().isEmpty()) |
205 return; | 206 return; |
206 ASSERT(m_nameToGroupMap); | 207 ASSERT(m_nameToGroupMap); |
207 if (!m_nameToGroupMap) | 208 if (!m_nameToGroupMap) |
208 return; | 209 return; |
209 RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); | 210 RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); |
210 ASSERT(group); | 211 ASSERT(group); |
211 group->updateCheckedState(element); | 212 group->updateCheckedState(element); |
212 } | 213 } |
213 | 214 |
214 void CheckedRadioButtons::requiredAttributeChanged(HTMLInputElement* element) | 215 void CheckedRadioButtons::requiredAttributeChanged(Handle<HTMLInputElement> elem
ent) |
215 { | 216 { |
216 ASSERT(element->isRadioButton()); | 217 ASSERT(element->isRadioButton()); |
217 if (element->name().isEmpty()) | 218 if (element->name().isEmpty()) |
218 return; | 219 return; |
219 ASSERT(m_nameToGroupMap); | 220 ASSERT(m_nameToGroupMap); |
220 if (!m_nameToGroupMap) | 221 if (!m_nameToGroupMap) |
221 return; | 222 return; |
222 RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); | 223 RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); |
223 ASSERT(group); | 224 ASSERT(group); |
224 group->requiredAttributeChanged(element); | 225 group->requiredAttributeChanged(element); |
225 } | 226 } |
226 | 227 |
227 HTMLInputElement* CheckedRadioButtons::checkedButtonForGroup(const AtomicString&
name) const | 228 Result<HTMLInputElement> CheckedRadioButtons::checkedButtonForGroup(const Atomic
String& name) const |
228 { | 229 { |
229 if (!m_nameToGroupMap) | 230 if (!m_nameToGroupMap) |
230 return 0; | 231 return nullptr; |
231 m_nameToGroupMap->checkConsistency(); | 232 m_nameToGroupMap->checkConsistency(); |
232 RadioButtonGroup* group = m_nameToGroupMap->get(name.impl()); | 233 RadioButtonGroup* group = m_nameToGroupMap->get(name.impl()); |
233 return group ? group->checkedButton() : 0; | 234 return group ? group->checkedButton() : nullptr; |
234 } | 235 } |
235 | 236 |
236 bool CheckedRadioButtons::isInRequiredGroup(HTMLInputElement* element) const | 237 bool CheckedRadioButtons::isInRequiredGroup(Handle<HTMLInputElement> element) co
nst |
237 { | 238 { |
238 ASSERT(element->isRadioButton()); | 239 ASSERT(element->isRadioButton()); |
239 if (element->name().isEmpty()) | 240 if (element->name().isEmpty()) |
240 return false; | 241 return false; |
241 if (!m_nameToGroupMap) | 242 if (!m_nameToGroupMap) |
242 return false; | 243 return false; |
243 RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); | 244 RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); |
244 return group && group->isRequired() && group->contains(element); | 245 return group && group->isRequired() && group->contains(element); |
245 } | 246 } |
246 | 247 |
247 void CheckedRadioButtons::removeButton(HTMLInputElement* element) | 248 void CheckedRadioButtons::removeButton(Handle<HTMLInputElement> element) |
248 { | 249 { |
249 ASSERT(element->isRadioButton()); | 250 ASSERT(element->isRadioButton()); |
250 if (element->name().isEmpty()) | 251 if (element->name().isEmpty()) |
251 return; | 252 return; |
252 if (!m_nameToGroupMap) | 253 if (!m_nameToGroupMap) |
253 return; | 254 return; |
254 | 255 |
255 m_nameToGroupMap->checkConsistency(); | 256 m_nameToGroupMap->checkConsistency(); |
256 NameToGroupMap::iterator it = m_nameToGroupMap->find(element->name().impl())
; | 257 NameToGroupMap::iterator it = m_nameToGroupMap->find(element->name().impl())
; |
257 if (it == m_nameToGroupMap->end()) | 258 if (it == m_nameToGroupMap->end()) |
258 return; | 259 return; |
259 it->value->remove(element); | 260 it->value->remove(element); |
260 if (it->value->isEmpty()) { | 261 if (it->value->isEmpty()) { |
261 // FIXME: We may skip deallocating the empty RadioButtonGroup for | 262 // FIXME: We may skip deallocating the empty RadioButtonGroup for |
262 // performance improvement. If we do so, we need to change the key type | 263 // performance improvement. If we do so, we need to change the key type |
263 // of m_nameToGroupMap from AtomicStringImpl* to RefPtr<AtomicStringImpl
>. | 264 // of m_nameToGroupMap from AtomicStringImpl* to RefPtr<AtomicStringImpl
>. |
264 m_nameToGroupMap->remove(it); | 265 m_nameToGroupMap->remove(it); |
265 if (m_nameToGroupMap->isEmpty()) | 266 if (m_nameToGroupMap->isEmpty()) |
266 m_nameToGroupMap.clear(); | 267 m_nameToGroupMap.clear(); |
267 } | 268 } |
268 } | 269 } |
269 | 270 |
270 } // namespace | 271 } // namespace |
OLD | NEW |