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

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

Issue 1632493002: Precisely account for required buttons in a radio group. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix oilpan compilation Created 4 years, 11 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
« no previous file with comments | « third_party/WebKit/LayoutTests/fast/forms/radio/radio-group-remove-required-expected.txt ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "wtf/HashSet.h" 25 #include "wtf/HashMap.h"
26 26
27 namespace blink { 27 namespace blink {
28 28
29 class RadioButtonGroup : public NoBaseWillBeGarbageCollected<RadioButtonGroup> { 29 class RadioButtonGroup : public NoBaseWillBeGarbageCollected<RadioButtonGroup> {
30 USING_FAST_MALLOC_WILL_BE_REMOVED(RadioButtonGroup); 30 USING_FAST_MALLOC_WILL_BE_REMOVED(RadioButtonGroup);
31 public: 31 public:
32 static PassOwnPtrWillBeRawPtr<RadioButtonGroup> create(); 32 static PassOwnPtrWillBeRawPtr<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 HTMLInputElement* checkedButton() const { return m_checkedButton; }
36 void add(HTMLInputElement*); 36 void add(HTMLInputElement*);
37 void updateCheckedState(HTMLInputElement*); 37 void updateCheckedState(HTMLInputElement*);
38 void requiredAttributeChanged(HTMLInputElement*); 38 void requiredAttributeChanged(HTMLInputElement*);
39 void remove(HTMLInputElement*); 39 void remove(HTMLInputElement*);
40 bool contains(HTMLInputElement*) const; 40 bool contains(HTMLInputElement*) const;
41 41
42 DECLARE_TRACE(); 42 DECLARE_TRACE();
43 43
44 private: 44 private:
45 RadioButtonGroup(); 45 RadioButtonGroup();
46 void setNeedsValidityCheckForAllButtons(); 46 void setNeedsValidityCheckForAllButtons();
47 bool isValid() const; 47 bool isValid() const;
48 void setCheckedButton(HTMLInputElement*); 48 void setCheckedButton(HTMLInputElement*);
49 49
50 WillBeHeapHashSet<RawPtrWillBeMember<HTMLInputElement>> m_members; 50 // The map records the 'required' state of each (button) element.
51 using Members = WillBeHeapHashMap<RawPtrWillBeMember<HTMLInputElement>, bool >;
52
53 #if ENABLE(OILPAN)
54 using MemberKeyValue = WTF::KeyValuePair<Member<HTMLInputElement>, bool>;
55 #else
56 using MemberKeyValue = WTF::KeyValuePair<HTMLInputElement*, bool>;
57 #endif
58
59 void updateRequiredButton(MemberKeyValue&, bool isRequired);
60
61 Members m_members;
51 RawPtrWillBeMember<HTMLInputElement> m_checkedButton; 62 RawPtrWillBeMember<HTMLInputElement> m_checkedButton;
52 size_t m_requiredCount; 63 size_t m_requiredCount;
53 }; 64 };
54 65
55 RadioButtonGroup::RadioButtonGroup() 66 RadioButtonGroup::RadioButtonGroup()
56 : m_checkedButton(nullptr) 67 : m_checkedButton(nullptr)
57 , m_requiredCount(0) 68 , m_requiredCount(0)
58 { 69 {
59 } 70 }
60 71
(...skipping 10 matching lines...) Expand all
71 void RadioButtonGroup::setCheckedButton(HTMLInputElement* button) 82 void RadioButtonGroup::setCheckedButton(HTMLInputElement* button)
72 { 83 {
73 HTMLInputElement* oldCheckedButton = m_checkedButton; 84 HTMLInputElement* oldCheckedButton = m_checkedButton;
74 if (oldCheckedButton == button) 85 if (oldCheckedButton == button)
75 return; 86 return;
76 m_checkedButton = button; 87 m_checkedButton = button;
77 if (oldCheckedButton) 88 if (oldCheckedButton)
78 oldCheckedButton->setChecked(false); 89 oldCheckedButton->setChecked(false);
79 } 90 }
80 91
92 void RadioButtonGroup::updateRequiredButton(MemberKeyValue& it, bool isRequired)
93 {
94 if (it.value == isRequired)
95 return;
96
97 it.value = isRequired;
98 if (isRequired) {
99 m_requiredCount++;
100 } else {
101 ASSERT(m_requiredCount);
102 m_requiredCount--;
103 }
104 }
105
81 void RadioButtonGroup::add(HTMLInputElement* button) 106 void RadioButtonGroup::add(HTMLInputElement* button)
82 { 107 {
83 ASSERT(button->type() == InputTypeNames::radio); 108 ASSERT(button->type() == InputTypeNames::radio);
84 if (!m_members.add(button).isNewEntry) 109 auto addResult = m_members.add(button, false);
110 if (!addResult.isNewEntry)
85 return; 111 return;
86 bool groupWasValid = isValid(); 112 bool groupWasValid = isValid();
87 if (button->isRequired()) 113 updateRequiredButton(*addResult.storedValue, button->isRequired());
88 ++m_requiredCount;
89 if (button->checked()) 114 if (button->checked())
90 setCheckedButton(button); 115 setCheckedButton(button);
91 116
92 bool groupIsValid = isValid(); 117 bool groupIsValid = isValid();
93 if (groupWasValid != groupIsValid) { 118 if (groupWasValid != groupIsValid) {
94 setNeedsValidityCheckForAllButtons(); 119 setNeedsValidityCheckForAllButtons();
95 } else if (!groupIsValid) { 120 } else if (!groupIsValid) {
96 // A radio button not in a group is always valid. We need to make it 121 // A radio button not in a group is always valid. We need to make it
97 // invalid only if the group is invalid. 122 // invalid only if the group is invalid.
98 button->setNeedsValidityCheck(); 123 button->setNeedsValidityCheck();
99 } 124 }
100 } 125 }
101 126
102 void RadioButtonGroup::updateCheckedState(HTMLInputElement* button) 127 void RadioButtonGroup::updateCheckedState(HTMLInputElement* button)
103 { 128 {
104 ASSERT(button->type() == InputTypeNames::radio); 129 ASSERT(button->type() == InputTypeNames::radio);
105 ASSERT(m_members.contains(button)); 130 ASSERT(m_members.contains(button));
106 bool wasValid = isValid(); 131 bool wasValid = isValid();
107 if (button->checked()) { 132 if (button->checked()) {
108 setCheckedButton(button); 133 setCheckedButton(button);
109 } else { 134 } else {
110 if (m_checkedButton == button) 135 if (m_checkedButton == button)
111 m_checkedButton = nullptr; 136 m_checkedButton = nullptr;
112 } 137 }
113 if (wasValid != isValid()) 138 if (wasValid != isValid())
114 setNeedsValidityCheckForAllButtons(); 139 setNeedsValidityCheckForAllButtons();
115 for (HTMLInputElement* const inputElement : m_members) { 140 for (auto& member : m_members) {
141 HTMLInputElement* const inputElement = member.key;
116 inputElement->pseudoStateChanged(CSSSelector::PseudoIndeterminate); 142 inputElement->pseudoStateChanged(CSSSelector::PseudoIndeterminate);
117 } 143 }
118 } 144 }
119 145
120 void RadioButtonGroup::requiredAttributeChanged(HTMLInputElement* button) 146 void RadioButtonGroup::requiredAttributeChanged(HTMLInputElement* button)
121 { 147 {
122 ASSERT(button->type() == InputTypeNames::radio); 148 ASSERT(button->type() == InputTypeNames::radio);
123 ASSERT(m_members.contains(button)); 149 auto it = m_members.find(button);
150 ASSERT(it != m_members.end());
124 bool wasValid = isValid(); 151 bool wasValid = isValid();
125 if (button->isRequired()) { 152 // Synchronize the 'required' flag for the button, along with
126 ++m_requiredCount; 153 // updating the overall count.
127 } else { 154 updateRequiredButton(*it, button->isRequired());
128 ASSERT(m_requiredCount);
129 --m_requiredCount;
130 }
131 if (wasValid != isValid()) 155 if (wasValid != isValid())
132 setNeedsValidityCheckForAllButtons(); 156 setNeedsValidityCheckForAllButtons();
133 } 157 }
134 158
135 void RadioButtonGroup::remove(HTMLInputElement* button) 159 void RadioButtonGroup::remove(HTMLInputElement* button)
136 { 160 {
137 ASSERT(button->type() == InputTypeNames::radio); 161 ASSERT(button->type() == InputTypeNames::radio);
138 WillBeHeapHashSet<RawPtrWillBeMember<HTMLInputElement>>::iterator it = m_mem bers.find(button); 162 auto it = m_members.find(button);
139 if (it == m_members.end()) 163 if (it == m_members.end())
140 return; 164 return;
141 bool wasValid = isValid(); 165 bool wasValid = isValid();
166 ASSERT(it->value == button->isRequired());
167 updateRequiredButton(*it, false);
142 m_members.remove(it); 168 m_members.remove(it);
143 if (button->isRequired()) {
144 ASSERT(m_requiredCount);
145 --m_requiredCount;
146 }
147 if (m_checkedButton == button) 169 if (m_checkedButton == button)
148 m_checkedButton = nullptr; 170 m_checkedButton = nullptr;
149 171
150 if (m_members.isEmpty()) { 172 if (m_members.isEmpty()) {
151 ASSERT(!m_requiredCount); 173 ASSERT(!m_requiredCount);
152 ASSERT(!m_checkedButton); 174 ASSERT(!m_checkedButton);
153 } else if (wasValid != isValid()) { 175 } else if (wasValid != isValid()) {
154 setNeedsValidityCheckForAllButtons(); 176 setNeedsValidityCheckForAllButtons();
155 } 177 }
156 if (!wasValid) { 178 if (!wasValid) {
157 // A radio button not in a group is always valid. We need to make it 179 // A radio button not in a group is always valid. We need to make it
158 // valid only if the group was invalid. 180 // valid only if the group was invalid.
159 button->setNeedsValidityCheck(); 181 button->setNeedsValidityCheck();
160 } 182 }
161 } 183 }
162 184
163 void RadioButtonGroup::setNeedsValidityCheckForAllButtons() 185 void RadioButtonGroup::setNeedsValidityCheckForAllButtons()
164 { 186 {
165 for (HTMLInputElement* const button : m_members) { 187 for (auto& element : m_members) {
188 HTMLInputElement* const button = element.key;
166 ASSERT(button->type() == InputTypeNames::radio); 189 ASSERT(button->type() == InputTypeNames::radio);
167 button->setNeedsValidityCheck(); 190 button->setNeedsValidityCheck();
168 } 191 }
169 } 192 }
170 193
171 bool RadioButtonGroup::contains(HTMLInputElement* button) const 194 bool RadioButtonGroup::contains(HTMLInputElement* button) const
172 { 195 {
173 return m_members.contains(button); 196 return m_members.contains(button);
174 } 197 }
175 198
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 } 298 }
276 299
277 DEFINE_TRACE(RadioButtonGroupScope) 300 DEFINE_TRACE(RadioButtonGroupScope)
278 { 301 {
279 #if ENABLE(OILPAN) 302 #if ENABLE(OILPAN)
280 visitor->trace(m_nameToGroupMap); 303 visitor->trace(m_nameToGroupMap);
281 #endif 304 #endif
282 } 305 }
283 306
284 } // namespace 307 } // namespace
OLDNEW
« no previous file with comments | « third_party/WebKit/LayoutTests/fast/forms/radio/radio-group-remove-required-expected.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698