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

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: added AXRadioInput 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/dom/NodeTraversal.h"
24 #include "core/html/HTMLInputElement.h" 25 #include "core/html/HTMLInputElement.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 void setNeedToUpdate(bool);
43 void updateAXPosition();
44 unsigned sizeOfMembers() const;
41 45
42 DECLARE_TRACE(); 46 DECLARE_TRACE();
43 47
44 private: 48 private:
45 RadioButtonGroup(); 49 RadioButtonGroup();
46 void setNeedsValidityCheckForAllButtons(); 50 void setNeedsValidityCheckForAllButtons();
47 bool isValid() const; 51 bool isValid() const;
48 void setCheckedButton(HTMLInputElement*); 52 void setCheckedButton(HTMLInputElement*);
53 bool isNextPosition(HTMLInputElement* list, HTMLInputElement* current) const ;
49 54
50 // The map records the 'required' state of each (button) element. 55 // The map records the 'required' state of each (button) element.
51 using Members = WillBeHeapHashMap<RawPtrWillBeMember<HTMLInputElement>, bool >; 56 using Members = WillBeHeapHashMap<RawPtrWillBeMember<HTMLInputElement>, bool >;
52 57
53 #if ENABLE(OILPAN) 58 #if ENABLE(OILPAN)
54 using MemberKeyValue = WTF::KeyValuePair<Member<HTMLInputElement>, bool>; 59 using MemberKeyValue = WTF::KeyValuePair<Member<HTMLInputElement>, bool>;
55 #else 60 #else
56 using MemberKeyValue = WTF::KeyValuePair<HTMLInputElement*, bool>; 61 using MemberKeyValue = WTF::KeyValuePair<HTMLInputElement*, bool>;
57 #endif 62 #endif
58 63
59 void updateRequiredButton(MemberKeyValue&, bool isRequired); 64 void updateRequiredButton(MemberKeyValue&, bool isRequired);
60 65
61 Members m_members; 66 Members m_members;
62 RawPtrWillBeMember<HTMLInputElement> m_checkedButton; 67 RawPtrWillBeMember<HTMLInputElement> m_checkedButton;
63 size_t m_requiredCount; 68 size_t m_requiredCount;
69 bool m_needToUpdateAXPosition;
64 }; 70 };
65 71
66 RadioButtonGroup::RadioButtonGroup() 72 RadioButtonGroup::RadioButtonGroup()
67 : m_checkedButton(nullptr) 73 : m_checkedButton(nullptr)
68 , m_requiredCount(0) 74 , m_requiredCount(0)
75 , m_needToUpdateAXPosition(false)
69 { 76 {
70 } 77 }
71 78
72 PassOwnPtrWillBeRawPtr<RadioButtonGroup> RadioButtonGroup::create() 79 PassOwnPtrWillBeRawPtr<RadioButtonGroup> RadioButtonGroup::create()
73 { 80 {
74 return adoptPtrWillBeNoop(new RadioButtonGroup); 81 return adoptPtrWillBeNoop(new RadioButtonGroup);
75 } 82 }
76 83
77 inline bool RadioButtonGroup::isValid() const 84 inline bool RadioButtonGroup::isValid() const
78 { 85 {
79 return !isRequired() || m_checkedButton; 86 return !isRequired() || m_checkedButton;
80 } 87 }
81 88
82 void RadioButtonGroup::setCheckedButton(HTMLInputElement* button) 89 void RadioButtonGroup::setCheckedButton(HTMLInputElement* button)
83 { 90 {
84 HTMLInputElement* oldCheckedButton = m_checkedButton; 91 HTMLInputElement* oldCheckedButton = m_checkedButton;
85 if (oldCheckedButton == button) 92 if (oldCheckedButton == button)
86 return; 93 return;
87 m_checkedButton = button; 94 m_checkedButton = button;
88 if (oldCheckedButton) 95 if (oldCheckedButton)
89 oldCheckedButton->setChecked(false); 96 oldCheckedButton->setChecked(false);
90 } 97 }
91 98
99 bool RadioButtonGroup::isNextPosition(HTMLInputElement* listItem, HTMLInputEleme nt* current) const
100 {
101 Node* commonAncestor = NodeTraversal::commonAncestor(*listItem, *current);
102 for (Node* node = commonAncestor; node; node = NodeTraversal::next(*node)) {
103 if (!node->isHTMLElement() || !isHTMLInputElement(node) || !toHTMLInputE lement(node)->isRadioButton())
104 continue;
105 if (node == listItem)
106 return true;
107 if (node == current)
108 return false;
109 }
110 return true;
111 }
112
92 void RadioButtonGroup::updateRequiredButton(MemberKeyValue& it, bool isRequired) 113 void RadioButtonGroup::updateRequiredButton(MemberKeyValue& it, bool isRequired)
93 { 114 {
94 if (it.value == isRequired) 115 if (it.value == isRequired)
95 return; 116 return;
96 117
97 it.value = isRequired; 118 it.value = isRequired;
98 if (isRequired) { 119 if (isRequired) {
99 m_requiredCount++; 120 m_requiredCount++;
100 } else { 121 } else {
101 ASSERT(m_requiredCount); 122 ASSERT(m_requiredCount);
102 m_requiredCount--; 123 m_requiredCount--;
103 } 124 }
104 } 125 }
105 126
106 void RadioButtonGroup::add(HTMLInputElement* button) 127 void RadioButtonGroup::add(HTMLInputElement* button)
107 { 128 {
108 ASSERT(button->type() == InputTypeNames::radio); 129 ASSERT(button->type() == InputTypeNames::radio);
109 auto addResult = m_members.add(button, false); 130 auto addResult = m_members.add(button, false);
110 if (!addResult.isNewEntry) 131 if (!addResult.isNewEntry)
111 return; 132 return;
133
134 setNeedToUpdate(true);
112 bool groupWasValid = isValid(); 135 bool groupWasValid = isValid();
113 updateRequiredButton(*addResult.storedValue, button->isRequired()); 136 updateRequiredButton(*addResult.storedValue, button->isRequired());
114 if (button->checked()) 137 if (button->checked())
115 setCheckedButton(button); 138 setCheckedButton(button);
116 139
117 bool groupIsValid = isValid(); 140 bool groupIsValid = isValid();
118 if (groupWasValid != groupIsValid) { 141 if (groupWasValid != groupIsValid) {
119 setNeedsValidityCheckForAllButtons(); 142 setNeedsValidityCheckForAllButtons();
120 } else if (!groupIsValid) { 143 } else if (!groupIsValid) {
121 // A radio button not in a group is always valid. We need to make it 144 // 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()) 178 if (wasValid != isValid())
156 setNeedsValidityCheckForAllButtons(); 179 setNeedsValidityCheckForAllButtons();
157 } 180 }
158 181
159 void RadioButtonGroup::remove(HTMLInputElement* button) 182 void RadioButtonGroup::remove(HTMLInputElement* button)
160 { 183 {
161 ASSERT(button->type() == InputTypeNames::radio); 184 ASSERT(button->type() == InputTypeNames::radio);
162 auto it = m_members.find(button); 185 auto it = m_members.find(button);
163 if (it == m_members.end()) 186 if (it == m_members.end())
164 return; 187 return;
188
189 setNeedToUpdate(true);
165 bool wasValid = isValid(); 190 bool wasValid = isValid();
166 ASSERT(it->value == button->isRequired()); 191 ASSERT(it->value == button->isRequired());
167 updateRequiredButton(*it, false); 192 updateRequiredButton(*it, false);
168 m_members.remove(it); 193 m_members.remove(it);
169 if (m_checkedButton == button) 194 if (m_checkedButton == button)
170 m_checkedButton = nullptr; 195 m_checkedButton = nullptr;
171 196
172 if (m_members.isEmpty()) { 197 if (m_members.isEmpty()) {
173 ASSERT(!m_requiredCount); 198 ASSERT(!m_requiredCount);
174 ASSERT(!m_checkedButton); 199 ASSERT(!m_checkedButton);
(...skipping 14 matching lines...) Expand all
189 ASSERT(button->type() == InputTypeNames::radio); 214 ASSERT(button->type() == InputTypeNames::radio);
190 button->setNeedsValidityCheck(); 215 button->setNeedsValidityCheck();
191 } 216 }
192 } 217 }
193 218
194 bool RadioButtonGroup::contains(HTMLInputElement* button) const 219 bool RadioButtonGroup::contains(HTMLInputElement* button) const
195 { 220 {
196 return m_members.contains(button); 221 return m_members.contains(button);
197 } 222 }
198 223
224 void RadioButtonGroup::setNeedToUpdate(bool set)
225 {
226 m_needToUpdateAXPosition = set;
227 }
228
229 void RadioButtonGroup::updateAXPosition()
230 {
231 if (!m_needToUpdateAXPosition)
232 return;
233
234 WillBeHeapVector<RawPtrWillBeMember<HTMLInputElement>> orderdList;
235 for (auto& element : m_members) {
236 HTMLInputElement* const current = element.key;
237 if (orderdList.isEmpty()) {
238 orderdList.append(current);
239 } else {
240 unsigned position = 0;
241 for (auto& item : orderdList) {
242 if (!isNextPosition(item, current))
keishi 2016/02/23 09:43:00 This reordering is like O(N^3). Could we use Radio
je_julie(Not used) 2016/02/27 14:01:08 I moved handling position for AX to AXRadioInput a
243 break;
244 position++;
245 }
246 orderdList.insert(position, current);
247 }
248 }
249
250 unsigned index = 0;
251 for (auto& orderedNode : orderdList) {
252 index++;
253 if (AXObjectCache* cache = orderedNode->document().existingAXObjectCache ())
254 cache->radiobuttonPositionChanged(orderedNode, index);
255 }
256 setNeedToUpdate(false);
257 }
258
259 unsigned RadioButtonGroup::sizeOfMembers() const
260 {
261 return m_members.size();
262 }
263
199 DEFINE_TRACE(RadioButtonGroup) 264 DEFINE_TRACE(RadioButtonGroup)
200 { 265 {
201 #if ENABLE(OILPAN) 266 #if ENABLE(OILPAN)
202 visitor->trace(m_members); 267 visitor->trace(m_members);
203 visitor->trace(m_checkedButton); 268 visitor->trace(m_checkedButton);
204 #endif 269 #endif
205 } 270 }
206 271
207 // ---------------------------------------------------------------- 272 // ----------------------------------------------------------------
208 273
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 { 335 {
271 ASSERT(element->type() == InputTypeNames::radio); 336 ASSERT(element->type() == InputTypeNames::radio);
272 if (element->name().isEmpty()) 337 if (element->name().isEmpty())
273 return false; 338 return false;
274 if (!m_nameToGroupMap) 339 if (!m_nameToGroupMap)
275 return false; 340 return false;
276 RadioButtonGroup* group = m_nameToGroupMap->get(element->name()); 341 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
277 return group && group->isRequired() && group->contains(element); 342 return group && group->isRequired() && group->contains(element);
278 } 343 }
279 344
345 unsigned RadioButtonGroupScope::sizeOfGroup(const HTMLInputElement* element) con st
346 {
347 if (!m_nameToGroupMap)
348 return 0;
349
350 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
351 if (!group)
352 return 0;
353 return group->sizeOfMembers();
354 }
355
356 void RadioButtonGroupScope::updateAXPositionInGroup(const HTMLInputElement* elem ent) const
357 {
358 if (!m_nameToGroupMap)
359 return;
360
361 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
362 if (!group)
363 return;
364 group->updateAXPosition();
365 }
366
367 void RadioButtonGroupScope::setNeedToUpdateAXPositionInGroup(const HTMLInputElem ent* element, bool set) const
368 {
369 if (!m_nameToGroupMap)
370 return;
371
372 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
373 if (!group)
374 return;
375 group->setNeedToUpdate(set);
keishi 2016/02/23 09:43:00 If we do something like RadioInputType::findNextFo
je_julie(Not used) 2016/02/27 14:01:08 I removed almost all handling to AXRadioInput as y
376 }
377
280 void RadioButtonGroupScope::removeButton(HTMLInputElement* element) 378 void RadioButtonGroupScope::removeButton(HTMLInputElement* element)
281 { 379 {
282 ASSERT(element->type() == InputTypeNames::radio); 380 ASSERT(element->type() == InputTypeNames::radio);
283 if (element->name().isEmpty()) 381 if (element->name().isEmpty())
284 return; 382 return;
285 if (!m_nameToGroupMap) 383 if (!m_nameToGroupMap)
286 return; 384 return;
287 385
288 RadioButtonGroup* group = m_nameToGroupMap->get(element->name()); 386 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
289 if (!group) 387 if (!group)
290 return; 388 return;
291 group->remove(element); 389 group->remove(element);
292 if (group->isEmpty()) { 390 if (group->isEmpty()) {
293 // We don't remove an empty RadioButtonGroup from m_nameToGroupMap for 391 // We don't remove an empty RadioButtonGroup from m_nameToGroupMap for
294 // better performance. 392 // better performance.
295 ASSERT(!group->isRequired()); 393 ASSERT(!group->isRequired());
296 ASSERT_WITH_SECURITY_IMPLICATION(!group->checkedButton()); 394 ASSERT_WITH_SECURITY_IMPLICATION(!group->checkedButton());
297 } 395 }
298 } 396 }
299 397
300 DEFINE_TRACE(RadioButtonGroupScope) 398 DEFINE_TRACE(RadioButtonGroupScope)
301 { 399 {
302 #if ENABLE(OILPAN) 400 #if ENABLE(OILPAN)
303 visitor->trace(m_nameToGroupMap); 401 visitor->trace(m_nameToGroupMap);
304 #endif 402 #endif
305 } 403 }
306 404
307 } // namespace blink 405 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698