Chromium Code Reviews| Index: third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp |
| diff --git a/third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp b/third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp |
| index a09c6707046e34edadc476c3c5790a4a56f06f03..d92beb735012ca5aaa124f8d21b9822aa92b62ec 100644 |
| --- a/third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp |
| +++ b/third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp |
| @@ -21,6 +21,7 @@ |
| #include "core/html/forms/RadioButtonGroupScope.h" |
| #include "core/InputTypeNames.h" |
| +#include "core/dom/NodeTraversal.h" |
| #include "core/html/HTMLInputElement.h" |
| #include "wtf/HashMap.h" |
| @@ -38,6 +39,9 @@ public: |
| void requiredAttributeChanged(HTMLInputElement*); |
| void remove(HTMLInputElement*); |
| bool contains(HTMLInputElement*) const; |
| + void setNeedToUpdate(bool); |
| + void updateAXPosition(); |
| + unsigned sizeOfMembers() const; |
| DECLARE_TRACE(); |
| @@ -46,6 +50,7 @@ private: |
| void setNeedsValidityCheckForAllButtons(); |
| bool isValid() const; |
| void setCheckedButton(HTMLInputElement*); |
| + bool isNextPosition(HTMLInputElement* list, HTMLInputElement* current) const; |
| // The map records the 'required' state of each (button) element. |
| using Members = WillBeHeapHashMap<RawPtrWillBeMember<HTMLInputElement>, bool>; |
| @@ -61,11 +66,13 @@ private: |
| Members m_members; |
| RawPtrWillBeMember<HTMLInputElement> m_checkedButton; |
| size_t m_requiredCount; |
| + bool m_needToUpdateAXPosition; |
| }; |
| RadioButtonGroup::RadioButtonGroup() |
| : m_checkedButton(nullptr) |
| , m_requiredCount(0) |
| + , m_needToUpdateAXPosition(false) |
| { |
| } |
| @@ -89,6 +96,20 @@ void RadioButtonGroup::setCheckedButton(HTMLInputElement* button) |
| oldCheckedButton->setChecked(false); |
| } |
| +bool RadioButtonGroup::isNextPosition(HTMLInputElement* listItem, HTMLInputElement* current) const |
| +{ |
| + Node* commonAncestor = NodeTraversal::commonAncestor(*listItem, *current); |
| + for (Node* node = commonAncestor; node; node = NodeTraversal::next(*node)) { |
| + if (!node->isHTMLElement() || !isHTMLInputElement(node) || !toHTMLInputElement(node)->isRadioButton()) |
| + continue; |
| + if (node == listItem) |
| + return true; |
| + if (node == current) |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| void RadioButtonGroup::updateRequiredButton(MemberKeyValue& it, bool isRequired) |
| { |
| if (it.value == isRequired) |
| @@ -109,6 +130,8 @@ void RadioButtonGroup::add(HTMLInputElement* button) |
| auto addResult = m_members.add(button, false); |
| if (!addResult.isNewEntry) |
| return; |
| + |
| + setNeedToUpdate(true); |
| bool groupWasValid = isValid(); |
| updateRequiredButton(*addResult.storedValue, button->isRequired()); |
| if (button->checked()) |
| @@ -162,6 +185,8 @@ void RadioButtonGroup::remove(HTMLInputElement* button) |
| auto it = m_members.find(button); |
| if (it == m_members.end()) |
| return; |
| + |
| + setNeedToUpdate(true); |
| bool wasValid = isValid(); |
| ASSERT(it->value == button->isRequired()); |
| updateRequiredButton(*it, false); |
| @@ -196,6 +221,46 @@ bool RadioButtonGroup::contains(HTMLInputElement* button) const |
| return m_members.contains(button); |
| } |
| +void RadioButtonGroup::setNeedToUpdate(bool set) |
| +{ |
| + m_needToUpdateAXPosition = set; |
| +} |
| + |
| +void RadioButtonGroup::updateAXPosition() |
| +{ |
| + if (!m_needToUpdateAXPosition) |
| + return; |
| + |
| + WillBeHeapVector<RawPtrWillBeMember<HTMLInputElement>> orderdList; |
| + for (auto& element : m_members) { |
| + HTMLInputElement* const current = element.key; |
| + if (orderdList.isEmpty()) { |
| + orderdList.append(current); |
| + } else { |
| + unsigned position = 0; |
| + for (auto& item : orderdList) { |
| + 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
|
| + break; |
| + position++; |
| + } |
| + orderdList.insert(position, current); |
| + } |
| + } |
| + |
| + unsigned index = 0; |
| + for (auto& orderedNode : orderdList) { |
| + index++; |
| + if (AXObjectCache* cache = orderedNode->document().existingAXObjectCache()) |
| + cache->radiobuttonPositionChanged(orderedNode, index); |
| + } |
| + setNeedToUpdate(false); |
| +} |
| + |
| +unsigned RadioButtonGroup::sizeOfMembers() const |
| +{ |
| + return m_members.size(); |
| +} |
| + |
| DEFINE_TRACE(RadioButtonGroup) |
| { |
| #if ENABLE(OILPAN) |
| @@ -277,6 +342,39 @@ bool RadioButtonGroupScope::isInRequiredGroup(HTMLInputElement* element) const |
| return group && group->isRequired() && group->contains(element); |
| } |
| +unsigned RadioButtonGroupScope::sizeOfGroup(const HTMLInputElement* element) const |
| +{ |
| + if (!m_nameToGroupMap) |
| + return 0; |
| + |
| + RadioButtonGroup* group = m_nameToGroupMap->get(element->name()); |
| + if (!group) |
| + return 0; |
| + return group->sizeOfMembers(); |
| +} |
| + |
| +void RadioButtonGroupScope::updateAXPositionInGroup(const HTMLInputElement* element) const |
| +{ |
| + if (!m_nameToGroupMap) |
| + return; |
| + |
| + RadioButtonGroup* group = m_nameToGroupMap->get(element->name()); |
| + if (!group) |
| + return; |
| + group->updateAXPosition(); |
| +} |
| + |
| +void RadioButtonGroupScope::setNeedToUpdateAXPositionInGroup(const HTMLInputElement* element, bool set) const |
| +{ |
| + if (!m_nameToGroupMap) |
| + return; |
| + |
| + RadioButtonGroup* group = m_nameToGroupMap->get(element->name()); |
| + if (!group) |
| + return; |
| + 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
|
| +} |
| + |
| void RadioButtonGroupScope::removeButton(HTMLInputElement* element) |
| { |
| ASSERT(element->type() == InputTypeNames::radio); |