| 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..d98a3de67c60124fe448afdbac295ae4fe6334d9 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/NodeComputedStyle.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;
|
| + unsigned sizeOfMembers() const;
|
| + void updatePosition();
|
| + void needUpdatePosition() { m_needToUpdateIndex = true; }
|
|
|
| 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_needToUpdateIndex;
|
| };
|
|
|
| RadioButtonGroup::RadioButtonGroup()
|
| : m_checkedButton(nullptr)
|
| , m_requiredCount(0)
|
| + , m_needToUpdateIndex(false)
|
| {
|
| }
|
|
|
| @@ -109,6 +116,8 @@ void RadioButtonGroup::add(HTMLInputElement* button)
|
| auto addResult = m_members.add(button, false);
|
| if (!addResult.isNewEntry)
|
| return;
|
| +
|
| + needUpdatePosition();
|
| bool groupWasValid = isValid();
|
| updateRequiredButton(*addResult.storedValue, button->isRequired());
|
| if (button->checked())
|
| @@ -162,6 +171,8 @@ void RadioButtonGroup::remove(HTMLInputElement* button)
|
| auto it = m_members.find(button);
|
| if (it == m_members.end())
|
| return;
|
| +
|
| + needUpdatePosition();
|
| bool wasValid = isValid();
|
| ASSERT(it->value == button->isRequired());
|
| updateRequiredButton(*it, false);
|
| @@ -196,6 +207,61 @@ bool RadioButtonGroup::contains(HTMLInputElement* button) const
|
| return m_members.contains(button);
|
| }
|
|
|
| +void RadioButtonGroup::updatePosition()
|
| +{
|
| + if (!m_needToUpdateIndex)
|
| + return;
|
| +
|
| + WillBeHeapVector<RawPtrWillBeMember<HTMLInputElement>> orderd;
|
| + for (auto& element : m_members) {
|
| + HTMLInputElement* const current = element.key;
|
| + ASSERT(current->type() == InputTypeNames::radio);
|
| + if (orderd.isEmpty()) {
|
| + orderd.append(current);
|
| + } else {
|
| + unsigned position = 0;
|
| + for (auto& item : orderd) {
|
| + if (!isNextPosition(item, current))
|
| + break;
|
| + position++;
|
| + }
|
| + orderd.insert(position, current);
|
| + }
|
| + }
|
| +
|
| + unsigned index = 0;
|
| + for (auto& orderedList : orderd) {
|
| + index++;
|
| + orderedList->setPositionInRadioGroup(index);
|
| + }
|
| + m_needToUpdateIndex = false;
|
| +}
|
| +
|
| +bool RadioButtonGroup::isNextPosition(HTMLInputElement* listItem, HTMLInputElement* current) const
|
| +{
|
| + if (!current->layoutObject() || !listItem->layoutObject())
|
| + return true;
|
| +
|
| + IntRect itemRect = listItem->layoutObject()->absoluteBoundingBoxRect();
|
| + IntRect currentRect = current->layoutObject()->absoluteBoundingBoxRect();
|
| + if (itemRect.y() < currentRect.y())
|
| + return true;
|
| + if (itemRect.y() == currentRect.y()) {
|
| + Node* commonAncestor = NodeTraversal::commonAncestor(*listItem, *current);
|
| + if (const ComputedStyle* style = commonAncestor->computedStyle()) {
|
| + if ((style->isLeftToRightDirection() && itemRect.x() <= currentRect.x())
|
| + || (!style->isLeftToRightDirection() && itemRect.x() >= currentRect.x()))
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +unsigned RadioButtonGroup::sizeOfMembers() const
|
| +{
|
| + return m_members.size();
|
| +}
|
| +
|
| DEFINE_TRACE(RadioButtonGroup)
|
| {
|
| #if ENABLE(OILPAN)
|
| @@ -277,6 +343,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::updateGroupPosition(const HTMLInputElement* element) const
|
| +{
|
| + if (!m_nameToGroupMap)
|
| + return;
|
| +
|
| + RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
|
| + if (!group)
|
| + return;
|
| + group->updatePosition();
|
| +}
|
| +
|
| +void RadioButtonGroupScope::needUpdatePositionGroup(const HTMLInputElement* element) const
|
| +{
|
| + if (!m_nameToGroupMap)
|
| + return;
|
| +
|
| + RadioButtonGroup* group = m_nameToGroupMap->get(element->name());
|
| + if (!group)
|
| + return;
|
| + group->needUpdatePosition();
|
| +}
|
| +
|
| void RadioButtonGroupScope::removeButton(HTMLInputElement* element)
|
| {
|
| ASSERT(element->type() == InputTypeNames::radio);
|
|
|