Deploy smart pointers in RadioButtonGroups and RadioButtonGroup
https://bugs.webkit.org/show_bug.cgi?id=202942
Reviewed by Zalan Bujtas.
Use Ref & WeakPtr instead of raw pointers in RadioButtonGroups and RadioButtonGroup.
Also made RadioButtonGroups::m_nameToGroupMap a HashMap instead of a unique_ptr of HashMap
since RadioButtonGroups is lazily created in TreeScope as of r250708.
No new tests since there should be no observable behavioral change.
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::addRadioButtonGroupMembers const):
* dom/RadioButtonGroups.cpp:
(WebCore::RadioButtonGroup): Use WeakHashSet and WeakPtr instead of raw pointers.
(WebCore::RadioButtonGroup::isEmpty const):
(WebCore::RadioButtonGroup::checkedButton const):
(WebCore::RadioButtonGroup::members const):
(WebCore::RadioButtonGroup::setCheckedButton):
(WebCore::RadioButtonGroup::updateCheckedState):
(WebCore::RadioButtonGroup::requiredStateChanged):
(WebCore::RadioButtonGroup::remove):
(WebCore::RadioButtonGroup::setNeedsStyleRecalcForAllButtons):
(WebCore::RadioButtonGroup::updateValidityForAllButtons):
(WebCore::RadioButtonGroup::contains const):
(WebCore::RadioButtonGroups::addButton):
(WebCore::RadioButtonGroups::groupMembers const):
(WebCore::RadioButtonGroups::updateCheckedState):
(WebCore::RadioButtonGroups::requiredStateChanged):
(WebCore::RadioButtonGroups::checkedButtonForGroup const):
(WebCore::RadioButtonGroups::hasCheckedButton const):
(WebCore::RadioButtonGroups::isInRequiredGroup const):
(WebCore::RadioButtonGroups::removeButton):
* dom/RadioButtonGroups.h:
(WebCore::RadioButtonGroups):
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::radioButtonGroup const):
(WebCore::HTMLInputElement::checkedRadioButtonForGroup const):
* html/HTMLInputElement.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251110 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 0030d2d..76789f4 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,46 @@
+2019-10-14 Ryosuke Niwa <rniwa@webkit.org>
+
+ Deploy smart pointers in RadioButtonGroups and RadioButtonGroup
+ https://bugs.webkit.org/show_bug.cgi?id=202942
+
+ Reviewed by Zalan Bujtas.
+
+ Use Ref & WeakPtr instead of raw pointers in RadioButtonGroups and RadioButtonGroup.
+
+ Also made RadioButtonGroups::m_nameToGroupMap a HashMap instead of a unique_ptr of HashMap
+ since RadioButtonGroups is lazily created in TreeScope as of r250708.
+
+ No new tests since there should be no observable behavioral change.
+
+ * accessibility/AccessibilityRenderObject.cpp:
+ (WebCore::AccessibilityRenderObject::addRadioButtonGroupMembers const):
+ * dom/RadioButtonGroups.cpp:
+ (WebCore::RadioButtonGroup): Use WeakHashSet and WeakPtr instead of raw pointers.
+ (WebCore::RadioButtonGroup::isEmpty const):
+ (WebCore::RadioButtonGroup::checkedButton const):
+ (WebCore::RadioButtonGroup::members const):
+ (WebCore::RadioButtonGroup::setCheckedButton):
+ (WebCore::RadioButtonGroup::updateCheckedState):
+ (WebCore::RadioButtonGroup::requiredStateChanged):
+ (WebCore::RadioButtonGroup::remove):
+ (WebCore::RadioButtonGroup::setNeedsStyleRecalcForAllButtons):
+ (WebCore::RadioButtonGroup::updateValidityForAllButtons):
+ (WebCore::RadioButtonGroup::contains const):
+ (WebCore::RadioButtonGroups::addButton):
+ (WebCore::RadioButtonGroups::groupMembers const):
+ (WebCore::RadioButtonGroups::updateCheckedState):
+ (WebCore::RadioButtonGroups::requiredStateChanged):
+ (WebCore::RadioButtonGroups::checkedButtonForGroup const):
+ (WebCore::RadioButtonGroups::hasCheckedButton const):
+ (WebCore::RadioButtonGroups::isInRequiredGroup const):
+ (WebCore::RadioButtonGroups::removeButton):
+ * dom/RadioButtonGroups.h:
+ (WebCore::RadioButtonGroups):
+ * html/HTMLInputElement.cpp:
+ (WebCore::HTMLInputElement::radioButtonGroup const):
+ (WebCore::HTMLInputElement::checkedRadioButtonForGroup const):
+ * html/HTMLInputElement.h:
+
2019-10-14 David Quesada <david_quesada@apple.com>
Remove WebCore::IOSApplication::isWebApp()
diff --git a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
index e95228e..5334dc7 100644
--- a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
+++ b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
@@ -995,7 +995,7 @@
if (is<HTMLInputElement>(node)) {
HTMLInputElement& input = downcast<HTMLInputElement>(*node);
for (auto& radioSibling : input.radioButtonGroup()) {
- if (AccessibilityObject* object = axObjectCache()->getOrCreate(radioSibling))
+ if (AccessibilityObject* object = axObjectCache()->getOrCreate(radioSibling.ptr()))
linkedUIElements.append(object);
}
} else {
diff --git a/Source/WebCore/dom/RadioButtonGroups.cpp b/Source/WebCore/dom/RadioButtonGroups.cpp
index 61bbc4e..74b4f89 100644
--- a/Source/WebCore/dom/RadioButtonGroups.cpp
+++ b/Source/WebCore/dom/RadioButtonGroups.cpp
@@ -23,22 +23,23 @@
#include "HTMLInputElement.h"
#include "Range.h"
-#include <wtf/HashSet.h>
+#include <wtf/WeakHashSet.h>
+#include <wtf/WeakPtr.h>
namespace WebCore {
class RadioButtonGroup {
WTF_MAKE_FAST_ALLOCATED;
public:
- bool isEmpty() const { return m_members.isEmpty(); }
+ bool isEmpty() const { return m_members.computesEmpty(); }
bool isRequired() const { return m_requiredCount; }
- HTMLInputElement* checkedButton() const { return m_checkedButton; }
+ RefPtr<HTMLInputElement> checkedButton() const { return m_checkedButton.get(); }
void add(HTMLInputElement&);
void updateCheckedState(HTMLInputElement&);
void requiredStateChanged(HTMLInputElement&);
void remove(HTMLInputElement&);
bool contains(HTMLInputElement&) const;
- Vector<HTMLInputElement*> members() const;
+ Vector<Ref<HTMLInputElement>> members() const;
private:
void setNeedsStyleRecalcForAllButtons();
@@ -46,8 +47,8 @@
bool isValid() const;
void setCheckedButton(HTMLInputElement*);
- HashSet<HTMLInputElement*> m_members;
- HTMLInputElement* m_checkedButton { nullptr };
+ WeakHashSet<HTMLInputElement> m_members;
+ WeakPtr<HTMLInputElement> m_checkedButton;
size_t m_requiredCount { 0 };
};
@@ -56,25 +57,29 @@
return !isRequired() || m_checkedButton;
}
-Vector<HTMLInputElement*> RadioButtonGroup::members() const
+Vector<Ref<HTMLInputElement>> RadioButtonGroup::members() const
{
- auto members = copyToVector(m_members);
- std::sort(members.begin(), members.end(), documentOrderComparator);
- return members;
+ Vector<Ref<HTMLInputElement>> sortedMembers;
+ for (auto& memeber : m_members)
+ sortedMembers.append(memeber);
+ std::sort(sortedMembers.begin(), sortedMembers.end(), [](auto& a, auto& b) {
+ return documentOrderComparator(a.ptr(), b.ptr());
+ });
+ return sortedMembers;
}
void RadioButtonGroup::setCheckedButton(HTMLInputElement* button)
{
- RefPtr<HTMLInputElement> oldCheckedButton = m_checkedButton;
+ RefPtr<HTMLInputElement> oldCheckedButton = m_checkedButton.get();
if (oldCheckedButton == button)
return;
- bool hadCheckedButton = m_checkedButton;
+ bool hadCheckedButton = m_checkedButton.get();
bool willHaveCheckedButton = button;
if (hadCheckedButton != willHaveCheckedButton)
setNeedsStyleRecalcForAllButtons();
- m_checkedButton = button;
+ m_checkedButton = makeWeakPtr(button);
if (oldCheckedButton)
oldCheckedButton->setChecked(false);
}
@@ -103,7 +108,7 @@
void RadioButtonGroup::updateCheckedState(HTMLInputElement& button)
{
ASSERT(button.isRadioButton());
- ASSERT(m_members.contains(&button));
+ ASSERT(m_members.contains(button));
bool wasValid = isValid();
if (button.checked())
setCheckedButton(&button);
@@ -118,7 +123,7 @@
void RadioButtonGroup::requiredStateChanged(HTMLInputElement& button)
{
ASSERT(button.isRadioButton());
- ASSERT(m_members.contains(&button));
+ ASSERT(m_members.contains(button));
bool wasValid = isValid();
if (button.isRequired())
++m_requiredCount;
@@ -133,12 +138,11 @@
void RadioButtonGroup::remove(HTMLInputElement& button)
{
ASSERT(button.isRadioButton());
- auto it = m_members.find(&button);
- if (it == m_members.end())
+ if (!m_members.contains(button))
return;
bool wasValid = isValid();
- m_members.remove(it);
+ m_members.remove(button);
if (button.isRequired()) {
ASSERT(m_requiredCount);
--m_requiredCount;
@@ -151,7 +155,7 @@
}
}
- if (m_members.isEmpty()) {
+ if (m_members.computesEmpty()) {
ASSERT(!m_requiredCount);
ASSERT(!m_checkedButton);
} else if (wasValid != isValid())
@@ -166,22 +170,22 @@
void RadioButtonGroup::setNeedsStyleRecalcForAllButtons()
{
for (auto& button : m_members) {
- ASSERT(button->isRadioButton());
- button->invalidateStyleForSubtree();
+ ASSERT(button.isRadioButton());
+ button.invalidateStyleForSubtree();
}
}
void RadioButtonGroup::updateValidityForAllButtons()
{
for (auto& button : m_members) {
- ASSERT(button->isRadioButton());
- button->updateValidity();
+ ASSERT(button.isRadioButton());
+ button.updateValidity();
}
}
bool RadioButtonGroup::contains(HTMLInputElement& button) const
{
- return m_members.contains(&button);
+ return m_members.contains(button);
}
// ----------------------------------------------------------------
@@ -197,16 +201,13 @@
if (element.name().isEmpty())
return;
- if (!m_nameToGroupMap)
- m_nameToGroupMap = makeUnique<NameToGroupMap>();
-
- auto& group = m_nameToGroupMap->add(element.name().impl(), nullptr).iterator->value;
+ auto& group = m_nameToGroupMap.add(element.name().impl(), nullptr).iterator->value;
if (!group)
group = makeUnique<RadioButtonGroup>();
group->add(element);
}
-Vector<HTMLInputElement*> RadioButtonGroups::groupMembers(const HTMLInputElement& element) const
+Vector<Ref<HTMLInputElement>> RadioButtonGroups::groupMembers(const HTMLInputElement& element) const
{
ASSERT(element.isRadioButton());
if (!element.isRadioButton())
@@ -216,10 +217,7 @@
if (!name)
return { };
- if (!m_nameToGroupMap)
- return { };
-
- auto* group = m_nameToGroupMap->get(name);
+ auto* group = m_nameToGroupMap.get(name);
if (!group)
return { };
return group->members();
@@ -230,10 +228,7 @@
ASSERT(element.isRadioButton());
if (element.name().isEmpty())
return;
- ASSERT(m_nameToGroupMap);
- if (!m_nameToGroupMap)
- return;
- m_nameToGroupMap->get(element.name().impl())->updateCheckedState(element);
+ m_nameToGroupMap.get(element.name().impl())->updateCheckedState(element);
}
void RadioButtonGroups::requiredStateChanged(HTMLInputElement& element)
@@ -241,20 +236,15 @@
ASSERT(element.isRadioButton());
if (element.name().isEmpty())
return;
- ASSERT(m_nameToGroupMap);
- if (!m_nameToGroupMap)
- return;
- auto* group = m_nameToGroupMap->get(element.name().impl());
+ auto* group = m_nameToGroupMap.get(element.name().impl());
ASSERT(group);
group->requiredStateChanged(element);
}
-HTMLInputElement* RadioButtonGroups::checkedButtonForGroup(const AtomString& name) const
+RefPtr<HTMLInputElement> RadioButtonGroups::checkedButtonForGroup(const AtomString& name) const
{
- if (!m_nameToGroupMap)
- return nullptr;
- m_nameToGroupMap->checkConsistency();
- RadioButtonGroup* group = m_nameToGroupMap->get(name.impl());
+ m_nameToGroupMap.checkConsistency();
+ RadioButtonGroup* group = m_nameToGroupMap.get(name.impl());
return group ? group->checkedButton() : nullptr;
}
@@ -262,9 +252,9 @@
{
ASSERT(element.isRadioButton());
const AtomString& name = element.name();
- if (name.isEmpty() || !m_nameToGroupMap)
+ if (name.isEmpty())
return element.checked();
- return m_nameToGroupMap->get(name.impl())->checkedButton();
+ return m_nameToGroupMap.get(name.impl())->checkedButton();
}
bool RadioButtonGroups::isInRequiredGroup(HTMLInputElement& element) const
@@ -272,9 +262,7 @@
ASSERT(element.isRadioButton());
if (element.name().isEmpty())
return false;
- if (!m_nameToGroupMap)
- return false;
- auto* group = m_nameToGroupMap->get(element.name().impl());
+ auto* group = m_nameToGroupMap.get(element.name().impl());
return group && group->isRequired() && group->contains(element);
}
@@ -283,22 +271,14 @@
ASSERT(element.isRadioButton());
if (element.name().isEmpty())
return;
- if (!m_nameToGroupMap)
- return;
- m_nameToGroupMap->checkConsistency();
- auto it = m_nameToGroupMap->find(element.name().impl());
- if (it == m_nameToGroupMap->end())
+ m_nameToGroupMap.checkConsistency();
+ auto it = m_nameToGroupMap.find(element.name().impl());
+ if (it == m_nameToGroupMap.end())
return;
it->value->remove(element);
- if (it->value->isEmpty()) {
- // FIXME: We may skip deallocating the empty RadioButtonGroup for
- // performance improvement. If we do so, we need to change the key type
- // of m_nameToGroupMap from AtomStringImpl* to RefPtr<AtomStringImpl>.
- m_nameToGroupMap->remove(it);
- if (m_nameToGroupMap->isEmpty())
- m_nameToGroupMap = nullptr;
- }
+ if (it->value->isEmpty())
+ m_nameToGroupMap.remove(it);
}
} // namespace
diff --git a/Source/WebCore/dom/RadioButtonGroups.h b/Source/WebCore/dom/RadioButtonGroups.h
index 52b336f..ef87610 100644
--- a/Source/WebCore/dom/RadioButtonGroups.h
+++ b/Source/WebCore/dom/RadioButtonGroups.h
@@ -39,14 +39,14 @@
void updateCheckedState(HTMLInputElement&);
void requiredStateChanged(HTMLInputElement&);
void removeButton(HTMLInputElement&);
- HTMLInputElement* checkedButtonForGroup(const AtomString& groupName) const;
+ RefPtr<HTMLInputElement> checkedButtonForGroup(const AtomString& groupName) const;
bool hasCheckedButton(const HTMLInputElement&) const;
bool isInRequiredGroup(HTMLInputElement&) const;
- Vector<HTMLInputElement*> groupMembers(const HTMLInputElement&) const;
+ Vector<Ref<HTMLInputElement>> groupMembers(const HTMLInputElement&) const;
private:
- typedef HashMap<AtomStringImpl*, std::unique_ptr<RadioButtonGroup>> NameToGroupMap;
- std::unique_ptr<NameToGroupMap> m_nameToGroupMap;
+ typedef HashMap<AtomString, std::unique_ptr<RadioButtonGroup>> NameToGroupMap;
+ NameToGroupMap m_nameToGroupMap;
};
} // namespace WebCore
diff --git a/Source/WebCore/html/HTMLInputElement.cpp b/Source/WebCore/html/HTMLInputElement.cpp
index fb59207..ddf55b7 100644
--- a/Source/WebCore/html/HTMLInputElement.cpp
+++ b/Source/WebCore/html/HTMLInputElement.cpp
@@ -1898,7 +1898,7 @@
return false;
}
-Vector<HTMLInputElement*> HTMLInputElement::radioButtonGroup() const
+Vector<Ref<HTMLInputElement>> HTMLInputElement::radioButtonGroup() const
{
RadioButtonGroups* buttons = radioButtonGroups();
if (!buttons)
@@ -1906,7 +1906,7 @@
return buttons->groupMembers(*this);
}
-HTMLInputElement* HTMLInputElement::checkedRadioButtonForGroup() const
+RefPtr<HTMLInputElement> HTMLInputElement::checkedRadioButtonForGroup() const
{
if (RadioButtonGroups* buttons = radioButtonGroups())
return buttons->checkedButtonForGroup(name());
diff --git a/Source/WebCore/html/HTMLInputElement.h b/Source/WebCore/html/HTMLInputElement.h
index f868eee..efe58b0 100644
--- a/Source/WebCore/html/HTMLInputElement.h
+++ b/Source/WebCore/html/HTMLInputElement.h
@@ -279,8 +279,8 @@
void listAttributeTargetChanged();
#endif
- Vector<HTMLInputElement*> radioButtonGroup() const;
- HTMLInputElement* checkedRadioButtonForGroup() const;
+ Vector<Ref<HTMLInputElement>> radioButtonGroup() const;
+ RefPtr<HTMLInputElement> checkedRadioButtonForGroup() const;
bool isInRequiredRadioButtonGroup();
// Returns null if this isn't associated with any radio button group.
RadioButtonGroups* radioButtonGroups() const;