Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Side by Side Diff: third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp

Issue 1628283002: posinset and setsize for input type, radio, exposed in AX tree (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase and Update code Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "core/layout/LayoutObject.h"
25 #include "wtf/HashMap.h" 26 #include "wtf/HashMap.h"
26 27
27 namespace blink { 28 namespace blink {
28 29
29 class RadioButtonGroup : public NoBaseWillBeGarbageCollected<RadioButtonGroup> { 30 class RadioButtonGroup : public NoBaseWillBeGarbageCollected<RadioButtonGroup> {
30 USING_FAST_MALLOC_WILL_BE_REMOVED(RadioButtonGroup); 31 USING_FAST_MALLOC_WILL_BE_REMOVED(RadioButtonGroup);
31 public: 32 public:
32 static PassOwnPtrWillBeRawPtr<RadioButtonGroup> create(); 33 static PassOwnPtrWillBeRawPtr<RadioButtonGroup> create();
33 bool isEmpty() const { return m_members.isEmpty(); } 34 bool isEmpty() const { return m_members.isEmpty(); }
34 bool isRequired() const { return m_requiredCount; } 35 bool isRequired() const { return m_requiredCount; }
35 HTMLInputElement* checkedButton() const { return m_checkedButton; } 36 HTMLInputElement* checkedButton() const { return m_checkedButton; }
36 void add(HTMLInputElement*); 37 void add(HTMLInputElement*);
37 void updateCheckedState(HTMLInputElement*); 38 void updateCheckedState(HTMLInputElement*);
38 void requiredAttributeChanged(HTMLInputElement*); 39 void requiredAttributeChanged(HTMLInputElement*);
39 void remove(HTMLInputElement*); 40 void remove(HTMLInputElement*);
40 bool contains(HTMLInputElement*) const; 41 bool contains(HTMLInputElement*) const;
42 unsigned sizeOfMembers() const;
43 void updatePosition() const;
41 44
42 DECLARE_TRACE(); 45 DECLARE_TRACE();
43 46
44 private: 47 private:
45 RadioButtonGroup(); 48 RadioButtonGroup();
46 void setNeedsValidityCheckForAllButtons(); 49 void setNeedsValidityCheckForAllButtons();
47 bool isValid() const; 50 bool isValid() const;
48 void setCheckedButton(HTMLInputElement*); 51 void setCheckedButton(HTMLInputElement*);
52 bool isNext(HTMLInputElement* list, HTMLInputElement* current) const;
keishi 2016/02/05 03:05:26 nit: Could you make the method name more specific
je_julie(Not used) 2016/02/13 03:19:00 I updated it with isNextPosition().
49 53
50 // The map records the 'required' state of each (button) element. 54 // The map records the 'required' state of each (button) element.
51 using Members = WillBeHeapHashMap<RawPtrWillBeMember<HTMLInputElement>, bool >; 55 using Members = WillBeHeapHashMap<RawPtrWillBeMember<HTMLInputElement>, bool >;
52 56
53 #if ENABLE(OILPAN) 57 #if ENABLE(OILPAN)
54 using MemberKeyValue = WTF::KeyValuePair<Member<HTMLInputElement>, bool>; 58 using MemberKeyValue = WTF::KeyValuePair<Member<HTMLInputElement>, bool>;
55 #else 59 #else
56 using MemberKeyValue = WTF::KeyValuePair<HTMLInputElement*, bool>; 60 using MemberKeyValue = WTF::KeyValuePair<HTMLInputElement*, bool>;
57 #endif 61 #endif
58 62
59 void updateRequiredButton(MemberKeyValue&, bool isRequired); 63 void updateRequiredButton(MemberKeyValue&, bool isRequired);
60 64
61 Members m_members; 65 Members m_members;
62 RawPtrWillBeMember<HTMLInputElement> m_checkedButton; 66 RawPtrWillBeMember<HTMLInputElement> m_checkedButton;
63 size_t m_requiredCount; 67 size_t m_requiredCount;
68 bool m_needToUpdateIndex;
64 }; 69 };
65 70
66 RadioButtonGroup::RadioButtonGroup() 71 RadioButtonGroup::RadioButtonGroup()
67 : m_checkedButton(nullptr) 72 : m_checkedButton(nullptr)
68 , m_requiredCount(0) 73 , m_requiredCount(0)
74 , m_needToUpdateIndex(false)
69 { 75 {
70 } 76 }
71 77
72 PassOwnPtrWillBeRawPtr<RadioButtonGroup> RadioButtonGroup::create() 78 PassOwnPtrWillBeRawPtr<RadioButtonGroup> RadioButtonGroup::create()
73 { 79 {
74 return adoptPtrWillBeNoop(new RadioButtonGroup); 80 return adoptPtrWillBeNoop(new RadioButtonGroup);
75 } 81 }
76 82
77 inline bool RadioButtonGroup::isValid() const 83 inline bool RadioButtonGroup::isValid() const
78 { 84 {
(...skipping 23 matching lines...) Expand all
102 m_requiredCount--; 108 m_requiredCount--;
103 } 109 }
104 } 110 }
105 111
106 void RadioButtonGroup::add(HTMLInputElement* button) 112 void RadioButtonGroup::add(HTMLInputElement* button)
107 { 113 {
108 ASSERT(button->type() == InputTypeNames::radio); 114 ASSERT(button->type() == InputTypeNames::radio);
109 auto addResult = m_members.add(button, false); 115 auto addResult = m_members.add(button, false);
110 if (!addResult.isNewEntry) 116 if (!addResult.isNewEntry)
111 return; 117 return;
118
119 m_needToUpdateIndex = true;
112 bool groupWasValid = isValid(); 120 bool groupWasValid = isValid();
113 updateRequiredButton(*addResult.storedValue, button->isRequired()); 121 updateRequiredButton(*addResult.storedValue, button->isRequired());
114 if (button->checked()) 122 if (button->checked())
115 setCheckedButton(button); 123 setCheckedButton(button);
116 124
117 bool groupIsValid = isValid(); 125 bool groupIsValid = isValid();
118 if (groupWasValid != groupIsValid) { 126 if (groupWasValid != groupIsValid) {
119 setNeedsValidityCheckForAllButtons(); 127 setNeedsValidityCheckForAllButtons();
120 } else if (!groupIsValid) { 128 } else if (!groupIsValid) {
121 // A radio button not in a group is always valid. We need to make it 129 // A radio button not in a group is always valid. We need to make it
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 if (wasValid != isValid()) 163 if (wasValid != isValid())
156 setNeedsValidityCheckForAllButtons(); 164 setNeedsValidityCheckForAllButtons();
157 } 165 }
158 166
159 void RadioButtonGroup::remove(HTMLInputElement* button) 167 void RadioButtonGroup::remove(HTMLInputElement* button)
160 { 168 {
161 ASSERT(button->type() == InputTypeNames::radio); 169 ASSERT(button->type() == InputTypeNames::radio);
162 auto it = m_members.find(button); 170 auto it = m_members.find(button);
163 if (it == m_members.end()) 171 if (it == m_members.end())
164 return; 172 return;
173
174 m_needToUpdateIndex = true;
165 bool wasValid = isValid(); 175 bool wasValid = isValid();
166 ASSERT(it->value == button->isRequired()); 176 ASSERT(it->value == button->isRequired());
167 updateRequiredButton(*it, false); 177 updateRequiredButton(*it, false);
168 m_members.remove(it); 178 m_members.remove(it);
169 if (m_checkedButton == button) 179 if (m_checkedButton == button)
170 m_checkedButton = nullptr; 180 m_checkedButton = nullptr;
171 181
172 if (m_members.isEmpty()) { 182 if (m_members.isEmpty()) {
173 ASSERT(!m_requiredCount); 183 ASSERT(!m_requiredCount);
174 ASSERT(!m_checkedButton); 184 ASSERT(!m_checkedButton);
(...skipping 14 matching lines...) Expand all
189 ASSERT(button->type() == InputTypeNames::radio); 199 ASSERT(button->type() == InputTypeNames::radio);
190 button->setNeedsValidityCheck(); 200 button->setNeedsValidityCheck();
191 } 201 }
192 } 202 }
193 203
194 bool RadioButtonGroup::contains(HTMLInputElement* button) const 204 bool RadioButtonGroup::contains(HTMLInputElement* button) const
195 { 205 {
196 return m_members.contains(button); 206 return m_members.contains(button);
197 } 207 }
198 208
209 void RadioButtonGroup::updatePosition() const
210 {
211 if (!m_needToUpdateIndex)
keishi 2016/02/05 03:05:26 List order seems to rely on layout. Does m_needToU
je_julie(Not used) 2016/02/13 03:19:00 I also set this flag in LayoutBlockFlow::layoutBlo
212 return;
213
214 WillBeHeapVector<RawPtrWillBeMember<HTMLInputElement>> orderd;
215 for (auto& element : m_members) {
216 HTMLInputElement* const current = element.key;
217 ASSERT(current->type() == InputTypeNames::radio);
218 if (orderd.isEmpty()) {
219 orderd.append(current);
220 } else {
221 unsigned position = 0;
222 for (auto& orderedList : orderd) {
223 if (!isNext(orderedList, current))
224 break;
225 position++;
226 }
227 orderd.insert(position, current);
228 }
229 }
230
231 unsigned index = 0;
232 for (auto& orderedList : orderd) {
233 index++;
234 orderedList->setPositionInRadioGroup(index);
235 }
236 }
237
238 bool RadioButtonGroup::isNext(HTMLInputElement* list, HTMLInputElement* current) const
239 {
240 if (!current->layoutObject() || !list->layoutObject())
241 return true;
242
243 IntRect listRect = list->layoutObject()->absoluteBoundingBoxRect();
244 IntRect currentRect = current->layoutObject()->absoluteBoundingBoxRect();
245 if (listRect.y() < currentRect.y())
246 return true;
247 if (listRect.y() == currentRect.y() && listRect.x() <= currentRect.x())
keishi 2016/02/05 03:05:26 Just curious. Is this ok for rtl?
je_julie(Not used) 2016/02/13 03:19:00 Right. We have to consider RTL case as well. I upd
248 return true;
249 return false;
250 }
251
252 unsigned RadioButtonGroup::sizeOfMembers() const
253 {
254 return m_members.size();
255 }
256
199 DEFINE_TRACE(RadioButtonGroup) 257 DEFINE_TRACE(RadioButtonGroup)
200 { 258 {
201 #if ENABLE(OILPAN) 259 #if ENABLE(OILPAN)
202 visitor->trace(m_members); 260 visitor->trace(m_members);
203 visitor->trace(m_checkedButton); 261 visitor->trace(m_checkedButton);
204 #endif 262 #endif
205 } 263 }
206 264
207 // ---------------------------------------------------------------- 265 // ----------------------------------------------------------------
208 266
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 { 328 {
271 ASSERT(element->type() == InputTypeNames::radio); 329 ASSERT(element->type() == InputTypeNames::radio);
272 if (element->name().isEmpty()) 330 if (element->name().isEmpty())
273 return false; 331 return false;
274 if (!m_nameToGroupMap) 332 if (!m_nameToGroupMap)
275 return false; 333 return false;
276 RadioButtonGroup* group = m_nameToGroupMap->get(element->name()); 334 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
277 return group && group->isRequired() && group->contains(element); 335 return group && group->isRequired() && group->contains(element);
278 } 336 }
279 337
338 unsigned RadioButtonGroupScope::sizeOfGroup(HTMLInputElement* element) const
339 {
340 if (!m_nameToGroupMap)
341 return 0;
342
343 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
344 if (!group)
345 return 0;
346 return group->sizeOfMembers();
347 }
348
349 void RadioButtonGroupScope::updateGroupPosition(HTMLInputElement* element) const
350 {
351 if (!m_nameToGroupMap)
352 return;
353
354 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
355 if (!group)
356 return;
357 group->updatePosition();
358 }
359
280 void RadioButtonGroupScope::removeButton(HTMLInputElement* element) 360 void RadioButtonGroupScope::removeButton(HTMLInputElement* element)
281 { 361 {
282 ASSERT(element->type() == InputTypeNames::radio); 362 ASSERT(element->type() == InputTypeNames::radio);
283 if (element->name().isEmpty()) 363 if (element->name().isEmpty())
284 return; 364 return;
285 if (!m_nameToGroupMap) 365 if (!m_nameToGroupMap)
286 return; 366 return;
287 367
288 RadioButtonGroup* group = m_nameToGroupMap->get(element->name()); 368 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
289 if (!group) 369 if (!group)
290 return; 370 return;
291 group->remove(element); 371 group->remove(element);
292 if (group->isEmpty()) { 372 if (group->isEmpty()) {
293 // We don't remove an empty RadioButtonGroup from m_nameToGroupMap for 373 // We don't remove an empty RadioButtonGroup from m_nameToGroupMap for
294 // better performance. 374 // better performance.
295 ASSERT(!group->isRequired()); 375 ASSERT(!group->isRequired());
296 ASSERT_WITH_SECURITY_IMPLICATION(!group->checkedButton()); 376 ASSERT_WITH_SECURITY_IMPLICATION(!group->checkedButton());
297 } 377 }
298 } 378 }
299 379
300 DEFINE_TRACE(RadioButtonGroupScope) 380 DEFINE_TRACE(RadioButtonGroupScope)
301 { 381 {
302 #if ENABLE(OILPAN) 382 #if ENABLE(OILPAN)
303 visitor->trace(m_nameToGroupMap); 383 visitor->trace(m_nameToGroupMap);
304 #endif 384 #endif
305 } 385 }
306 386
307 } // namespace blink 387 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698