| 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..dfef5f440a2e0e75a1f1037a22f890c803168b51 | 
| --- /dev/null | 
| +++ b/third_party/WebKit/Source/core/dom/FormElementObserver.cpp | 
| @@ -0,0 +1,164 @@ | 
| +// 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/css/CSSComputedStyleDeclaration.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()); | 
| +      if (record->attributeName() == "action") { | 
| +        // If the action was modified, we just assume that the form as | 
| +        // submitted. | 
| +        element_observer_->NotifyMutation(element); | 
| +      } else { | 
| +        // Otherwise, either "style" or "class" was modified. Check the | 
| +        // computed style. | 
| +        CSSComputedStyleDeclaration* style = | 
| +            CSSComputedStyleDeclaration::Create(&element); | 
| +        if (style->GetPropertyValue(CSSPropertyDisplay) == "none") | 
| +          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); | 
| +  it->value->ElementWasHiddenOrRemoved(); | 
| +  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 | 
|  |