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); |