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

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: addressed review comments 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/NodeComputedStyle.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 unsigned sizeOfMembers() const;
43 void updatePosition();
44 void needUpdatePosition() { m_needToUpdateIndex = true; }
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_needToUpdateIndex;
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_needToUpdateIndex(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 {
(...skipping 23 matching lines...) Expand all
102 m_requiredCount--; 109 m_requiredCount--;
103 } 110 }
104 } 111 }
105 112
106 void RadioButtonGroup::add(HTMLInputElement* button) 113 void RadioButtonGroup::add(HTMLInputElement* button)
107 { 114 {
108 ASSERT(button->type() == InputTypeNames::radio); 115 ASSERT(button->type() == InputTypeNames::radio);
109 auto addResult = m_members.add(button, false); 116 auto addResult = m_members.add(button, false);
110 if (!addResult.isNewEntry) 117 if (!addResult.isNewEntry)
111 return; 118 return;
119
120 needUpdatePosition();
112 bool groupWasValid = isValid(); 121 bool groupWasValid = isValid();
113 updateRequiredButton(*addResult.storedValue, button->isRequired()); 122 updateRequiredButton(*addResult.storedValue, button->isRequired());
114 if (button->checked()) 123 if (button->checked())
115 setCheckedButton(button); 124 setCheckedButton(button);
116 125
117 bool groupIsValid = isValid(); 126 bool groupIsValid = isValid();
118 if (groupWasValid != groupIsValid) { 127 if (groupWasValid != groupIsValid) {
119 setNeedsValidityCheckForAllButtons(); 128 setNeedsValidityCheckForAllButtons();
120 } else if (!groupIsValid) { 129 } else if (!groupIsValid) {
121 // A radio button not in a group is always valid. We need to make it 130 // 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()) 164 if (wasValid != isValid())
156 setNeedsValidityCheckForAllButtons(); 165 setNeedsValidityCheckForAllButtons();
157 } 166 }
158 167
159 void RadioButtonGroup::remove(HTMLInputElement* button) 168 void RadioButtonGroup::remove(HTMLInputElement* button)
160 { 169 {
161 ASSERT(button->type() == InputTypeNames::radio); 170 ASSERT(button->type() == InputTypeNames::radio);
162 auto it = m_members.find(button); 171 auto it = m_members.find(button);
163 if (it == m_members.end()) 172 if (it == m_members.end())
164 return; 173 return;
174
175 needUpdatePosition();
165 bool wasValid = isValid(); 176 bool wasValid = isValid();
166 ASSERT(it->value == button->isRequired()); 177 ASSERT(it->value == button->isRequired());
167 updateRequiredButton(*it, false); 178 updateRequiredButton(*it, false);
168 m_members.remove(it); 179 m_members.remove(it);
169 if (m_checkedButton == button) 180 if (m_checkedButton == button)
170 m_checkedButton = nullptr; 181 m_checkedButton = nullptr;
171 182
172 if (m_members.isEmpty()) { 183 if (m_members.isEmpty()) {
173 ASSERT(!m_requiredCount); 184 ASSERT(!m_requiredCount);
174 ASSERT(!m_checkedButton); 185 ASSERT(!m_checkedButton);
(...skipping 14 matching lines...) Expand all
189 ASSERT(button->type() == InputTypeNames::radio); 200 ASSERT(button->type() == InputTypeNames::radio);
190 button->setNeedsValidityCheck(); 201 button->setNeedsValidityCheck();
191 } 202 }
192 } 203 }
193 204
194 bool RadioButtonGroup::contains(HTMLInputElement* button) const 205 bool RadioButtonGroup::contains(HTMLInputElement* button) const
195 { 206 {
196 return m_members.contains(button); 207 return m_members.contains(button);
197 } 208 }
198 209
210 void RadioButtonGroup::updatePosition()
211 {
212 if (!m_needToUpdateIndex)
213 return;
214
215 WillBeHeapVector<RawPtrWillBeMember<HTMLInputElement>> orderd;
216 for (auto& element : m_members) {
217 HTMLInputElement* const current = element.key;
218 ASSERT(current->type() == InputTypeNames::radio);
219 if (orderd.isEmpty()) {
220 orderd.append(current);
221 } else {
222 unsigned position = 0;
223 for (auto& item : orderd) {
224 if (!isNextPosition(item, current))
225 break;
226 position++;
227 }
228 orderd.insert(position, current);
229 }
230 }
231
232 unsigned index = 0;
233 for (auto& orderedList : orderd) {
234 index++;
235 orderedList->setPositionInRadioGroup(index);
236 }
237 m_needToUpdateIndex = false;
238 }
239
240 bool RadioButtonGroup::isNextPosition(HTMLInputElement* listItem, HTMLInputEleme nt* current) const
241 {
242 if (!current->layoutObject() || !listItem->layoutObject())
243 return true;
244
245 IntRect itemRect = listItem->layoutObject()->absoluteBoundingBoxRect();
246 IntRect currentRect = current->layoutObject()->absoluteBoundingBoxRect();
247 if (itemRect.y() < currentRect.y())
248 return true;
249 if (itemRect.y() == currentRect.y()) {
250 Node* commonAncestor = NodeTraversal::commonAncestor(*listItem, *current );
251 if (const ComputedStyle* style = commonAncestor->computedStyle()) {
252 if ((style->isLeftToRightDirection() && itemRect.x() <= currentRect. x())
253 || (!style->isLeftToRightDirection() && itemRect.x() >= currentR ect.x()))
254 return true;
255 }
256 }
257 return false;
258 }
259
260 unsigned RadioButtonGroup::sizeOfMembers() const
261 {
262 return m_members.size();
263 }
264
199 DEFINE_TRACE(RadioButtonGroup) 265 DEFINE_TRACE(RadioButtonGroup)
200 { 266 {
201 #if ENABLE(OILPAN) 267 #if ENABLE(OILPAN)
202 visitor->trace(m_members); 268 visitor->trace(m_members);
203 visitor->trace(m_checkedButton); 269 visitor->trace(m_checkedButton);
204 #endif 270 #endif
205 } 271 }
206 272
207 // ---------------------------------------------------------------- 273 // ----------------------------------------------------------------
208 274
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 { 336 {
271 ASSERT(element->type() == InputTypeNames::radio); 337 ASSERT(element->type() == InputTypeNames::radio);
272 if (element->name().isEmpty()) 338 if (element->name().isEmpty())
273 return false; 339 return false;
274 if (!m_nameToGroupMap) 340 if (!m_nameToGroupMap)
275 return false; 341 return false;
276 RadioButtonGroup* group = m_nameToGroupMap->get(element->name()); 342 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
277 return group && group->isRequired() && group->contains(element); 343 return group && group->isRequired() && group->contains(element);
278 } 344 }
279 345
346 unsigned RadioButtonGroupScope::sizeOfGroup(const HTMLInputElement* element) con st
347 {
348 if (!m_nameToGroupMap)
349 return 0;
350
351 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
352 if (!group)
353 return 0;
354 return group->sizeOfMembers();
355 }
356
357 void RadioButtonGroupScope::updateGroupPosition(const HTMLInputElement* element) const
358 {
359 if (!m_nameToGroupMap)
360 return;
361
362 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
363 if (!group)
364 return;
365 group->updatePosition();
366 }
367
368 void RadioButtonGroupScope::needUpdatePositionGroup(const HTMLInputElement* elem ent) const
369 {
370 if (!m_nameToGroupMap)
371 return;
372
373 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
374 if (!group)
375 return;
376 group->needUpdatePosition();
377 }
378
280 void RadioButtonGroupScope::removeButton(HTMLInputElement* element) 379 void RadioButtonGroupScope::removeButton(HTMLInputElement* element)
281 { 380 {
282 ASSERT(element->type() == InputTypeNames::radio); 381 ASSERT(element->type() == InputTypeNames::radio);
283 if (element->name().isEmpty()) 382 if (element->name().isEmpty())
284 return; 383 return;
285 if (!m_nameToGroupMap) 384 if (!m_nameToGroupMap)
286 return; 385 return;
287 386
288 RadioButtonGroup* group = m_nameToGroupMap->get(element->name()); 387 RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
289 if (!group) 388 if (!group)
290 return; 389 return;
291 group->remove(element); 390 group->remove(element);
292 if (group->isEmpty()) { 391 if (group->isEmpty()) {
293 // We don't remove an empty RadioButtonGroup from m_nameToGroupMap for 392 // We don't remove an empty RadioButtonGroup from m_nameToGroupMap for
294 // better performance. 393 // better performance.
295 ASSERT(!group->isRequired()); 394 ASSERT(!group->isRequired());
296 ASSERT_WITH_SECURITY_IMPLICATION(!group->checkedButton()); 395 ASSERT_WITH_SECURITY_IMPLICATION(!group->checkedButton());
297 } 396 }
298 } 397 }
299 398
300 DEFINE_TRACE(RadioButtonGroupScope) 399 DEFINE_TRACE(RadioButtonGroupScope)
301 { 400 {
302 #if ENABLE(OILPAN) 401 #if ENABLE(OILPAN)
303 visitor->trace(m_nameToGroupMap); 402 visitor->trace(m_nameToGroupMap);
304 #endif 403 #endif
305 } 404 }
306 405
307 } // namespace blink 406 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698