Index: third_party/WebKit/Source/core/dom/FormElementObserver.cpp |
diff --git a/third_party/WebKit/Source/core/dom/FormElementObserver.cpp b/third_party/WebKit/Source/core/dom/FormElementObserver.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ad69cfeba178dd9c8d5166c9f3a8db4f680d6253 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/dom/FormElementObserver.cpp |
@@ -0,0 +1,153 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "core/dom/FormElementObserver.h" |
+ |
+#include "core/dom/MutationCallback.h" |
+#include "core/dom/MutationObserver.h" |
+#include "core/dom/MutationObserverInit.h" |
+#include "core/dom/MutationRecord.h" |
+#include "core/dom/StaticNodeList.h" |
+#include "core/html/HTMLElement.h" |
+#include "core/html/HTMLFormElement.h" |
+#include "core/html/HTMLInputElement.h" |
+#include "public/web/WebElement.h" |
+#include "public/web/WebFormElementObserverCallback.h" |
+ |
+namespace blink { |
+ |
+class FormElementObserver::ObserverCallback : public MutationCallback { |
+ public: |
+ explicit ObserverCallback(FormElementObserver&); |
+ DECLARE_VIRTUAL_TRACE(); |
+ |
+ ExecutionContext* GetExecutionContext() const override; |
+ |
+ void Register(HTMLElement&); |
+ void Dispose(); |
+ |
+ private: |
+ void Call(const HeapVector<Member<MutationRecord>>& records, |
+ MutationObserver*) override; |
+ |
+ Member<FormElementObserver> element_observer_; |
+ Member<MutationObserver> mutation_observer_; |
+}; |
+ |
+FormElementObserver::ObserverCallback::ObserverCallback( |
+ FormElementObserver& element_observer) |
+ : element_observer_(element_observer) { |
+ mutation_observer_ = MutationObserver::Create(this); |
+} |
+ |
+ExecutionContext* FormElementObserver::ObserverCallback::GetExecutionContext() |
+ const { |
+ return element_observer_->document_; |
+} |
+ |
+void FormElementObserver::ObserverCallback::Register(HTMLElement& element) { |
+ { |
+ Vector<String> filter; |
+ filter.ReserveCapacity(3); |
+ filter.push_back(String("action")); |
+ filter.push_back(String("class")); |
+ filter.push_back(String("style")); |
+ MutationObserverInit init; |
+ init.setAttributes(true); |
+ init.setAttributeFilter(filter); |
+ mutation_observer_->observe(&element, init, ASSERT_NO_EXCEPTION); |
+ } |
+ { |
+ MutationObserverInit init; |
+ init.setChildList(true); |
+ mutation_observer_->observe(element.parentElement(), init, |
+ ASSERT_NO_EXCEPTION); |
+ } |
+} |
+ |
+void FormElementObserver::ObserverCallback::Dispose() { |
+ mutation_observer_->disconnect(); |
+} |
+ |
+void FormElementObserver::ObserverCallback::Call( |
+ const HeapVector<Member<MutationRecord>>& records, |
+ MutationObserver*) { |
+ for (const auto& record : records) { |
+ if (record->type() == "childList") { |
+ for (unsigned i = 0; i < record->removedNodes()->length(); ++i) { |
+ if (!record->removedNodes()->item(i)->IsHTMLElement()) |
+ continue; |
+ element_observer_->NotifyMutation( |
+ *ToHTMLElement(record->removedNodes()->item(i))); |
+ } |
+ } else { |
+ HTMLElement& element = *ToHTMLElement(record->target()); |
+ element_observer_->NotifyMutation(element); |
+ } |
+ } |
+} |
+ |
+DEFINE_TRACE(FormElementObserver::ObserverCallback) { |
+ visitor->Trace(element_observer_); |
+ visitor->Trace(mutation_observer_); |
+ MutationCallback::Trace(visitor); |
+} |
+ |
+FormElementObserver::FormElementObserver(Document& document) |
+ : document_(&document) {} |
+ |
+FormElementObserver::~FormElementObserver() {} |
+ |
+void FormElementObserver::EnsureObserver() { |
+ if (!callback_) |
+ callback_ = new ObserverCallback(*this); |
+} |
+ |
+void FormElementObserver::ClearObserver() { |
+ if (callback_) { |
+ callback_->Dispose(); |
+ callback_ = nullptr; |
+ } |
+} |
+ |
+void FormElementObserver::Observe( |
+ HTMLFormElement& element, |
+ std::unique_ptr<WebFormElementObserverCallback> callback) { |
+ ObserveInternal(element, std::move(callback)); |
+} |
+ |
+void FormElementObserver::Observe( |
+ HTMLInputElement& element, |
+ std::unique_ptr<WebFormElementObserverCallback> callback) { |
+ ObserveInternal(element, std::move(callback)); |
+} |
+ |
+void FormElementObserver::ObserveInternal( |
+ HTMLElement& element, |
+ std::unique_ptr<WebFormElementObserverCallback> callback) { |
+ DCHECK(element.parentElement()); |
+ CHECK(callbacks_.Set(&element, std::move(callback)).is_new_entry); |
+ EnsureObserver(); |
+ callback_->Register(element); |
+} |
+ |
+void FormElementObserver::NotifyMutation(HTMLElement& element) { |
+ if (!callbacks_.Contains(&element)) |
+ return; |
+ auto it = callbacks_.find(&element); |
+ if (!it->value->ShouldStopObserving()) |
jochen (gone - plz use gerrit)
2017/05/10 11:45:41
To avoid duplicating the logic to check whether we
|
+ return; |
+ callbacks_.erase(it); |
+ if (callbacks_.IsEmpty()) |
+ ClearObserver(); |
+} |
+ |
+DEFINE_TRACE(FormElementObserver) { |
+ visitor->Trace(document_); |
+ visitor->Trace(callback_); |
+ visitor->Trace(mutation_observer_); |
+ visitor->Trace(callbacks_); |
+} |
+ |
+} // namespace blink |