Create ReportingObserver and DeprecationReports.

This patch both implements ReportingObserver, and generates DeprecationReports to route to ReportingObservers.

See this explainer for more details on these features (working spec): https://github.com/WICG/reporting/blob/master/EXPLAINER.md

Intent to implement: https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/B1oztuLlzxg

Bug: 731810
Change-Id: If6ebab0aa106788b97f8ef5b0b64540171387923
Reviewed-on: https://chromium-review.googlesource.com/564016
Reviewed-by: Philip Rogers <pdr@chromium.org>
Reviewed-by: Nate Chapin <japhet@chromium.org>
Commit-Queue: Paul Meyer <paulmeyer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#489690}
diff --git a/third_party/WebKit/LayoutTests/reporting-observer/deprecation.html b/third_party/WebKit/LayoutTests/reporting-observer/deprecation.html
new file mode 100644
index 0000000..30e4123
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/reporting-observer/deprecation.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<p>ReportingObserver tests</p>
+<script src="resources/deprecation.js"></script>
diff --git a/third_party/WebKit/LayoutTests/reporting-observer/resources/deprecation.js b/third_party/WebKit/LayoutTests/reporting-observer/resources/deprecation.js
new file mode 100644
index 0000000..20509ff7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/reporting-observer/resources/deprecation.js
@@ -0,0 +1,25 @@
+async_test(function(test) {
+  var observer = new ReportingObserver(function(reports, observer) {
+    test.step(function() {
+      assert_equals(reports.length, 2);
+
+      // Ensure that the contents of the reports are valid.
+      for(let report of reports) {
+        assert_equals(report.type, "deprecation");
+        assert_true(report.url.endsWith(
+            "reporting-observer/deprecation.html"));
+        assert_true(report.body.sourceFile.endsWith(
+            "reporting-observer/resources/deprecation.js"));
+        assert_equals(typeof reports[0].body.lineNumber, "number");
+        assert_equals(typeof reports[0].body.message, "string");
+      }
+    });
+
+    test.done();
+  });
+  observer.observe();
+
+  // Use two deprecated features to generate two deprecation reports.
+  window.webkitStorageInfo;
+  window.getMatchedCSSRules();
+}, "Deprecation reports");
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
index 5474c39..713f160 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -5304,6 +5304,11 @@
     setter onconnect
     setter onconnecting
     setter ondisconnect
+interface ReportingObserver
+    attribute @@toStringTag
+    method constructor
+    method disconnect
+    method observe
 interface Request
     attribute @@toStringTag
     getter bodyUsed
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 427b428..24f29f9 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -5311,6 +5311,11 @@
     setter onconnect
     setter onconnecting
     setter ondisconnect
+interface ReportingObserver
+    attribute @@toStringTag
+    method constructor
+    method disconnect
+    method observe
 interface Request
     attribute @@toStringTag
     getter bodyUsed
diff --git a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
index 0a945c38..3a7fccf 100644
--- a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
@@ -111,6 +111,8 @@
   "$bindings_core_v8_output_dir/MojoWatchCallback.h",
   "$bindings_core_v8_output_dir/PerformanceObserverCallback.cpp",
   "$bindings_core_v8_output_dir/PerformanceObserverCallback.h",
+  "$bindings_core_v8_output_dir/ReportingObserverCallback.cpp",
+  "$bindings_core_v8_output_dir/ReportingObserverCallback.h",
   "$bindings_core_v8_output_dir/ResizeObserverCallback.cpp",
   "$bindings_core_v8_output_dir/ResizeObserverCallback.h",
 ]
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index dad0e11..10f8e87 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -160,9 +160,13 @@
                     "fileapi/FileReader.idl",
                     "fileapi/FileReaderSync.idl",
                     "frame/BarProp.idl",
+                    "frame/DeprecationReport.idl",
                     "frame/External.idl",
                     "frame/History.idl",
                     "frame/Location.idl",
+                    "frame/Report.idl",
+                    "frame/ReportBody.idl",
+                    "frame/ReportingObserver.idl",
                     "frame/VisualViewport.idl",
                     "geometry/DOMMatrix.idl",
                     "geometry/DOMMatrixReadOnly.idl",
diff --git a/third_party/WebKit/Source/core/frame/BUILD.gn b/third_party/WebKit/Source/core/frame/BUILD.gn
index 89816b3..4c5c925 100644
--- a/third_party/WebKit/Source/core/frame/BUILD.gn
+++ b/third_party/WebKit/Source/core/frame/BUILD.gn
@@ -29,6 +29,7 @@
     "DeprecatedScheduleStyleRecalcDuringLayout.h",
     "Deprecation.cpp",
     "Deprecation.h",
+    "DeprecationReport.h",
     "DeviceSingleWindowEventController.cpp",
     "DeviceSingleWindowEventController.h",
     "EmbeddedContentView.h",
@@ -100,6 +101,12 @@
     "RemoteFrameOwner.h",
     "RemoteFrameView.cpp",
     "RemoteFrameView.h",
+    "Report.h",
+    "ReportBody.h",
+    "ReportingContext.cpp",
+    "ReportingContext.h",
+    "ReportingObserver.cpp",
+    "ReportingObserver.h",
     "ResizeViewportAnchor.cpp",
     "ResizeViewportAnchor.h",
     "RootFrameViewport.cpp",
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index a3dfe70c..8981da6 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -6,8 +6,11 @@
 
 #include "core/dom/Document.h"
 #include "core/dom/ExecutionContext.h"
+#include "core/frame/DeprecationReport.h"
 #include "core/frame/FrameConsole.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/Report.h"
+#include "core/frame/ReportingContext.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/page/Page.h"
 #include "core/workers/WorkerOrWorkletGlobalScope.h"
@@ -149,11 +152,14 @@
 
   if (!page->GetUseCounter().HasRecordedMeasurement(feature)) {
     page->GetUseCounter().RecordMeasurement(feature);
-    DCHECK(!DeprecationMessage(feature).IsEmpty());
-    ConsoleMessage* console_message =
-        ConsoleMessage::Create(kDeprecationMessageSource, kWarningMessageLevel,
-                               DeprecationMessage(feature));
+    String message = DeprecationMessage(feature);
+
+    DCHECK(!message.IsEmpty());
+    ConsoleMessage* console_message = ConsoleMessage::Create(
+        kDeprecationMessageSource, kWarningMessageLevel, message);
     frame->Console().AddMessage(console_message);
+
+    GenerateReport(frame, message);
   }
 }
 
@@ -245,6 +251,22 @@
   }
 }
 
+void Deprecation::GenerateReport(const LocalFrame* frame,
+                                 const String& message) {
+  if (!frame || !frame->Client())
+    return;
+
+  Document* document = frame->GetDocument();
+  ReportingContext* reporting_context = ReportingContext::From(document);
+  if (!reporting_context->ObserverExists())
+    return;
+
+  // Send a deprecation report to any ReportingObservers.
+  ReportBody* body = new DeprecationReport(message, SourceLocation::Capture());
+  Report* report = new Report("deprecation", document->Url().GetString(), body);
+  reporting_context->QueueReport(report);
+}
+
 String Deprecation::DeprecationMessage(WebFeature feature) {
   switch (feature) {
     // Quota
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.h b/third_party/WebKit/Source/core/frame/Deprecation.h
index 361c8da..82aacf4 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.h
+++ b/third_party/WebKit/Source/core/frame/Deprecation.h
@@ -61,6 +61,9 @@
   // CSSPropertyIDs that aren't deprecated return an empty string.
   static String DeprecationMessage(CSSPropertyID unresolved_property);
 
+  // Generate a deprecation report, to be routed to any ReportingObservers.
+  static void GenerateReport(const LocalFrame*, const String& message);
+
   BitVector css_property_deprecation_bits_;
   unsigned mute_count_;
 };
diff --git a/third_party/WebKit/Source/core/frame/DeprecationReport.h b/third_party/WebKit/Source/core/frame/DeprecationReport.h
new file mode 100644
index 0000000..ee069e8
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/DeprecationReport.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef DeprecationReport_h
+#define DeprecationReport_h
+
+#include "bindings/core/v8/SourceLocation.h"
+#include "core/frame/ReportBody.h"
+
+namespace blink {
+
+class CORE_EXPORT DeprecationReport : public ReportBody {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  DeprecationReport(const String& message,
+                    std::unique_ptr<SourceLocation> location)
+      : message_(message), location_(std::move(location)) {}
+
+  ~DeprecationReport() override {}
+
+  String message() const { return message_; }
+  String sourceFile() const { return location_->Url(); }
+  long lineNumber() const { return location_->LineNumber(); }
+
+  DEFINE_INLINE_VIRTUAL_TRACE() { ReportBody::Trace(visitor); }
+
+ private:
+  const String message_;
+  std::unique_ptr<SourceLocation> location_;
+};
+
+}  // namespace blink
+
+#endif  // DeprecationReport_h
diff --git a/third_party/WebKit/Source/core/frame/DeprecationReport.idl b/third_party/WebKit/Source/core/frame/DeprecationReport.idl
new file mode 100644
index 0000000..6836be7a
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/DeprecationReport.idl
@@ -0,0 +1,15 @@
+// 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.
+
+// https://github.com/WICG/reporting/blob/master/EXPLAINER.md#reportingobserver---observing-reports-from-javascript
+
+[
+    NoInterfaceObject,
+    RuntimeEnabled=ReportingObserver
+] interface DeprecationReport : ReportBody {
+  // TODO(paulmeyer): Add additional data, including: id, anticipatedRemoval.
+  readonly attribute DOMString message;
+  readonly attribute DOMString sourceFile;
+  readonly attribute long lineNumber;
+};
diff --git a/third_party/WebKit/Source/core/frame/Report.h b/third_party/WebKit/Source/core/frame/Report.h
new file mode 100644
index 0000000..39ecd52
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/Report.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef Report_h
+#define Report_h
+
+#include "core/frame/ReportBody.h"
+
+namespace blink {
+
+class CORE_EXPORT Report : public GarbageCollectedFinalized<Report>,
+                           public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  Report(const String& type, const String& url, ReportBody* body)
+      : type_(type), url_(url), body_(body) {}
+
+  virtual ~Report() {}
+
+  String type() const { return type_; }
+  String url() const { return url_; }
+  ReportBody* body() const { return body_; }
+
+  DEFINE_INLINE_TRACE() { visitor->Trace(body_); }
+
+ private:
+  const String type_;
+  const String url_;
+  Member<ReportBody> body_;
+};
+
+}  // namespace blink
+
+#endif  // Report_h
diff --git a/third_party/WebKit/Source/core/frame/Report.idl b/third_party/WebKit/Source/core/frame/Report.idl
new file mode 100644
index 0000000..b1a271d
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/Report.idl
@@ -0,0 +1,14 @@
+// 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.
+
+// https://github.com/WICG/reporting/blob/master/EXPLAINER.md#reportingobserver---observing-reports-from-javascript
+
+[
+    NoInterfaceObject,
+    RuntimeEnabled=ReportingObserver
+] interface Report {
+    readonly attribute DOMString type;
+    readonly attribute DOMString url;
+    readonly attribute ReportBody? body;
+};
diff --git a/third_party/WebKit/Source/core/frame/ReportBody.h b/third_party/WebKit/Source/core/frame/ReportBody.h
new file mode 100644
index 0000000..fcf8faf
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/ReportBody.h
@@ -0,0 +1,24 @@
+// 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.
+
+#ifndef ReportBody_h
+#define ReportBody_h
+
+#include "platform/bindings/ScriptWrappable.h"
+
+namespace blink {
+
+class CORE_EXPORT ReportBody : public GarbageCollectedFinalized<ReportBody>,
+                               public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  virtual ~ReportBody() {}
+
+  DEFINE_INLINE_VIRTUAL_TRACE() {}
+};
+
+}  // namespace blink
+
+#endif  // ReportBody_h
diff --git a/third_party/WebKit/Source/core/frame/ReportBody.idl b/third_party/WebKit/Source/core/frame/ReportBody.idl
new file mode 100644
index 0000000..4ff3db08
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/ReportBody.idl
@@ -0,0 +1,11 @@
+// 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.
+
+// https://github.com/WICG/reporting/blob/master/EXPLAINER.md#reportingobserver---observing-reports-from-javascript
+
+[
+    NoInterfaceObject,
+    RuntimeEnabled=ReportingObserver
+] interface ReportBody {
+};
diff --git a/third_party/WebKit/Source/core/frame/ReportingContext.cpp b/third_party/WebKit/Source/core/frame/ReportingContext.cpp
new file mode 100644
index 0000000..502b2cab
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/ReportingContext.cpp
@@ -0,0 +1,80 @@
+// 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/frame/ReportingContext.h"
+
+#include "core/dom/ExecutionContext.h"
+#include "core/dom/TaskRunnerHelper.h"
+#include "core/frame/Report.h"
+#include "core/frame/ReportingObserver.h"
+#include "platform/WebTaskRunner.h"
+#include "platform/bindings/ScriptState.h"
+
+namespace blink {
+
+ReportingContext::ReportingContext(ExecutionContext& context)
+    : Supplement<ExecutionContext>(context), execution_context_(context) {}
+
+// static
+const char* ReportingContext::SupplementName() {
+  return "ReportingContext";
+}
+
+// static
+ReportingContext* ReportingContext::From(ExecutionContext* context) {
+  ReportingContext* reporting_context = static_cast<ReportingContext*>(
+      Supplement<ExecutionContext>::From(context, SupplementName()));
+  if (!reporting_context) {
+    reporting_context = new ReportingContext(*context);
+    Supplement<ExecutionContext>::ProvideTo(*context, SupplementName(),
+                                            reporting_context);
+  }
+  return reporting_context;
+}
+
+void ReportingContext::QueueReport(Report* report) {
+  if (!ObserverExists())
+    return;
+
+  reports_.push_back(report);
+
+  // When the first report of a batch is queued, make a task to report the whole
+  // batch (in the queue) to all ReportingObservers.
+  if (reports_.size() == 1) {
+    TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI, execution_context_)
+        ->PostTask(BLINK_FROM_HERE, WTF::Bind(&ReportingContext::SendReports,
+                                              WrapWeakPersistent(this)));
+  }
+}
+
+void ReportingContext::SendReports() {
+  // The reports queued to be sent to callbacks are copied (and cleared) before
+  // being sent to observers, since additional reports may be queued as a result
+  // of the callbacks.
+  auto reports_to_send = reports_;
+  reports_.clear();
+  for (auto observer : observers_)
+    observer->ReportToCallback(reports_to_send);
+}
+
+void ReportingContext::RegisterObserver(ReportingObserver* observer) {
+  observers_.insert(observer);
+}
+
+void ReportingContext::UnregisterObserver(ReportingObserver* observer) {
+  observers_.erase(observer);
+}
+
+bool ReportingContext::ObserverExists() {
+  return observers_.size();
+}
+
+DEFINE_TRACE(ReportingContext) {
+  visitor->Trace(observers_);
+  visitor->Trace(reports_);
+  visitor->Trace(execution_context_);
+  Supplement<ExecutionContext>::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/ReportingContext.h b/third_party/WebKit/Source/core/frame/ReportingContext.h
new file mode 100644
index 0000000..91c6f4f1
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/ReportingContext.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef ReportingContext_h
+#define ReportingContext_h
+
+#include "core/CoreExport.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/Supplementable.h"
+
+namespace blink {
+
+class ExecutionContext;
+class Report;
+class ReportingObserver;
+
+// ReportingContext is used as a container for all active ReportingObservers for
+// an ExecutionContext.
+class CORE_EXPORT ReportingContext final
+    : public GarbageCollectedFinalized<ReportingContext>,
+      public Supplement<ExecutionContext> {
+  USING_GARBAGE_COLLECTED_MIXIN(ReportingContext)
+ public:
+  explicit ReportingContext(ExecutionContext&);
+
+  static const char* SupplementName();
+
+  // Returns the ReportingContext for an ExecutionContext. If one does not
+  // already exist for the given context, one is created.
+  static ReportingContext* From(ExecutionContext*);
+
+  // Queues a report to be reported to all observers.
+  void QueueReport(Report*);
+
+  // Sends all queued reports to all observers.
+  void SendReports();
+
+  void RegisterObserver(ReportingObserver*);
+  void UnregisterObserver(ReportingObserver*);
+
+  // Returns whether there is at least one active ReportingObserver.
+  bool ObserverExists();
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  HeapListHashSet<Member<ReportingObserver>> observers_;
+  HeapVector<Member<Report>> reports_;
+  Member<ExecutionContext> execution_context_;
+};
+
+}  // namespace blink
+
+#endif  // ReportingContext_h
diff --git a/third_party/WebKit/Source/core/frame/ReportingObserver.cpp b/third_party/WebKit/Source/core/frame/ReportingObserver.cpp
new file mode 100644
index 0000000..ae93139a
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/ReportingObserver.cpp
@@ -0,0 +1,42 @@
+// 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/frame/ReportingObserver.h"
+
+#include "core/dom/ExecutionContext.h"
+#include "core/frame/Report.h"
+#include "core/frame/ReportingContext.h"
+#include "platform/bindings/ScriptState.h"
+
+namespace blink {
+
+ReportingObserver* ReportingObserver::Create(
+    ExecutionContext* execution_context,
+    ReportingObserverCallback* callback) {
+  return new ReportingObserver(execution_context, callback);
+}
+
+ReportingObserver::ReportingObserver(ExecutionContext* execution_context,
+                                     ReportingObserverCallback* callback)
+    : execution_context_(execution_context), callback_(callback) {}
+
+void ReportingObserver::ReportToCallback(
+    const HeapVector<Member<Report>>& reports) {
+  callback_->call(this, reports, this);
+}
+
+void ReportingObserver::observe() {
+  ReportingContext::From(execution_context_)->RegisterObserver(this);
+}
+
+void ReportingObserver::disconnect() {
+  ReportingContext::From(execution_context_)->UnregisterObserver(this);
+}
+
+DEFINE_TRACE(ReportingObserver) {
+  visitor->Trace(execution_context_);
+  visitor->Trace(callback_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/ReportingObserver.h b/third_party/WebKit/Source/core/frame/ReportingObserver.h
new file mode 100644
index 0000000..7047b97
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/ReportingObserver.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef ReportingObserver_h
+#define ReportingObserver_h
+
+#include "bindings/core/v8/ReportingObserverCallback.h"
+#include "core/CoreExport.h"
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/wtf/Vector.h"
+
+namespace blink {
+
+class ExecutionContext;
+class Report;
+class ReportingObserverCallback;
+
+class CORE_EXPORT ReportingObserver final
+    : public GarbageCollected<ReportingObserver>,
+      public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static ReportingObserver* Create(ExecutionContext*,
+                                   ReportingObserverCallback*);
+
+  // Call the callback with reports.
+  void ReportToCallback(const HeapVector<Member<Report>>& reports);
+
+  void observe();
+  void disconnect();
+
+  DECLARE_TRACE();
+
+ private:
+  explicit ReportingObserver(ExecutionContext*, ReportingObserverCallback*);
+
+  Member<ExecutionContext> execution_context_;
+  Member<ReportingObserverCallback> callback_;
+};
+
+}  // namespace blink
+
+#endif  // ReportingObserver_h
diff --git a/third_party/WebKit/Source/core/frame/ReportingObserver.idl b/third_party/WebKit/Source/core/frame/ReportingObserver.idl
new file mode 100644
index 0000000..f3cbb925
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/ReportingObserver.idl
@@ -0,0 +1,16 @@
+// 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.
+
+// https://github.com/WICG/reporting/blob/master/EXPLAINER.md#reportingobserver---observing-reports-from-javascript
+
+callback ReportingObserverCallback = void (sequence<Report> reports, ReportingObserver observer);
+
+[
+    Constructor(ReportingObserverCallback callback),
+    ConstructorCallWith=ExecutionContext,
+    RuntimeEnabled=ReportingObserver
+] interface ReportingObserver {
+    void observe();
+    void disconnect();
+};
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index dc85ef3b7..2b04f31 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -363,6 +363,10 @@
       status: "experimental",
     },
     {
+      name: "DeprecationReporting",
+      status: "experimental",
+    },
+    {
       name: "DesktopCaptureDisableLocalEchoControl",
       status: "experimental",
     },
@@ -895,6 +899,10 @@
       status: "stable",
     },
     {
+      name: "ReportingObserver",
+      status: "experimental",
+    },
+    {
       name: "ResizeObserver",
       status: "experimental",
     },