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