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

Unified Diff: third_party/WebKit/Source/core/html/HTMLSelectElement.cpp

Issue 1970653003: ExternalPopupMenu should recreate its popup only if a SELECT subtree is updated (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add an enum argument to updateFromElement Created 4 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index 391b5486f648de1f172eb69a84ebf8c90511dda4..6806b5382c39ec07aae0576b7d487ad397309db4 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -36,6 +36,9 @@
#include "core/dom/Attribute.h"
#include "core/dom/ElementTraversal.h"
#include "core/dom/ExecutionContextTask.h"
+#include "core/dom/MutationCallback.h"
+#include "core/dom/MutationObserver.h"
+#include "core/dom/MutationObserverInit.h"
#include "core/dom/NodeComputedStyle.h"
#include "core/dom/NodeListsNodeData.h"
#include "core/dom/NodeTraversal.h"
@@ -923,7 +926,7 @@ void HTMLSelectElement::setSuggestedIndex(int suggestedIndex)
scrollToOption(item(listToOptionIndex(suggestedIndex)));
}
if (popupIsVisible())
- m_popup->updateFromElement();
+ m_popup->updateFromElement(PopupMenu::BySelectionChange);
}
void HTMLSelectElement::scrollToOption(HTMLOptionElement* option)
@@ -1045,7 +1048,7 @@ void HTMLSelectElement::selectOption(HTMLOptionElement* element, int optionIndex
layoutObject->updateFromElement();
// PopupMenu::updateFromElement() posts an O(N) task.
if (popupIsVisible())
- m_popup->updateFromElement();
+ m_popup->updateFromElement(PopupMenu::BySelectionChange);
scrollToSelection();
setNeedsValidityCheck();
@@ -1825,6 +1828,7 @@ DEFINE_TRACE(HTMLSelectElement)
visitor->trace(m_activeSelectionEnd);
visitor->trace(m_optionToScrollTo);
visitor->trace(m_popup);
+ visitor->trace(m_popupUpdater);
HTMLFormControlElementWithState::trace(visitor);
}
@@ -1901,6 +1905,7 @@ LayoutUnit HTMLSelectElement::clientPaddingRight() const
void HTMLSelectElement::popupDidHide()
{
m_popupIsVisible = false;
+ unobserveTreeMutation();
if (AXObjectCache* cache = document().existingAXObjectCache()) {
if (layoutObject() && layoutObject()->isMenuList())
cache->didHideMenuListPopup(toLayoutMenuList(layoutObject()));
@@ -1960,6 +1965,7 @@ void HTMLSelectElement::showPopup()
if (!m_popup)
m_popup = document().frameHost()->chromeClient().openPopupMenu(*document().frame(), *this);
m_popupIsVisible = true;
+ observeTreeMutation();
LayoutMenuList* menuList = toLayoutMenuList(layoutObject());
m_popup->show();
@@ -1977,7 +1983,7 @@ void HTMLSelectElement::didRecalcStyle(StyleRecalcChange change)
{
HTMLFormControlElementWithState::didRecalcStyle(change);
if (popupIsVisible())
- m_popup->updateFromElement();
+ m_popup->updateFromElement(PopupMenu::ByStyleChange);
}
void HTMLSelectElement::detach(const AttachContext& context)
@@ -1987,6 +1993,7 @@ void HTMLSelectElement::detach(const AttachContext& context)
m_popup->disconnectClient();
m_popupIsVisible = false;
m_popup = nullptr;
+ unobserveTreeMutation();
}
void HTMLSelectElement::resetTypeAheadSessionForTesting()
@@ -1994,4 +2001,71 @@ void HTMLSelectElement::resetTypeAheadSessionForTesting()
m_typeAhead.resetSession();
}
+// PopupUpdater notifies updates of the specified SELECT element subtree to
+// a PopupMenu object.
+class HTMLSelectElement::PopupUpdater : public MutationCallback {
+public:
+ explicit PopupUpdater(HTMLSelectElement&);
+ DECLARE_VIRTUAL_TRACE();
+
+ void dispose()
+ {
+ m_observer->disconnect();
+ }
+
+private:
+ void call(const HeapVector<Member<MutationRecord>>&, MutationObserver*) override
+ {
+ m_select->didMutateSubtree();
+ }
+
+ ExecutionContext* getExecutionContext() const override
+ {
+ return &m_select->document();
+ }
+
+ Member<HTMLSelectElement> m_select;
+ Member<MutationObserver> m_observer;
+};
+
+HTMLSelectElement::PopupUpdater::PopupUpdater(HTMLSelectElement& select)
+ : m_select(select)
+{
+ m_observer = MutationObserver::create(this);
+ MutationObserverInit init;
+ init.setAttributes(true);
+ init.setCharacterData(true);
+ init.setChildList(true);
+ init.setSubtree(true);
+ m_observer->observe(&select, init, ASSERT_NO_EXCEPTION);
+}
+
+DEFINE_TRACE(HTMLSelectElement::PopupUpdater)
+{
+ visitor->trace(m_select);
+ visitor->trace(m_observer);
+ MutationCallback::trace(visitor);
+}
+
+void HTMLSelectElement::observeTreeMutation()
+{
+ DCHECK(!m_popupUpdater);
+ m_popupUpdater = new PopupUpdater(*this);
+}
+
+void HTMLSelectElement::unobserveTreeMutation()
+{
+ if (!m_popupUpdater)
+ return;
+ m_popupUpdater->dispose();
+ m_popupUpdater = nullptr;
+}
+
+void HTMLSelectElement::didMutateSubtree()
+{
+ DCHECK(popupIsVisible());
+ DCHECK(m_popup);
+ m_popup->updateFromElement(PopupMenu::ByDOMChange);
+}
+
} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/html/HTMLSelectElement.h ('k') | third_party/WebKit/Source/core/loader/EmptyClients.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698