Bug 1263722 - Implement performance navigation timing r=baku draft
authorValentin Gosu <valentin.gosu@gmail.com>
Sun, 17 Apr 2016 22:03:28 +0200
changeset 669861 42ef00dea8c7dff60743c1119faf4a76e8f59ae5
parent 669591 b44e80e0590e6eed86a1902365424673c8c2eaec
child 669862 3f1e91644849fa9568866c2898d13d8d75575cf4
push id81442
push uservalentin.gosu@gmail.com
push dateMon, 25 Sep 2017 13:08:30 +0000
reviewersbaku
bugs1263722
milestone58.0a1
Bug 1263722 - Implement performance navigation timing r=baku MozReview-Commit-ID: 9rJ3J6SqiDX * * * [mq]: test.patch MozReview-Commit-ID: IYXp5G3iNSi
dom/performance/Performance.cpp
dom/performance/Performance.h
dom/performance/PerformanceMainThread.cpp
dom/performance/PerformanceMainThread.h
dom/performance/PerformanceNavigationTiming.cpp
dom/performance/PerformanceNavigationTiming.h
dom/performance/PerformanceResourceTiming.cpp
dom/performance/PerformanceResourceTiming.h
dom/performance/moz.build
dom/webidl/PerformanceNavigationTiming.webidl
dom/webidl/moz.build
testing/web-platform/meta/navigation-timing/nav2_idlharness.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_document_open.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_document_replaced.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_frame_removed.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_instance_accessible_from_the_start.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_navigate_within_document.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_navigation_type_backforward.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_navigation_type_reload.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_redirect_server.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_redirect_xserver.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_unloadEvents_no_previous_document.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_unloadEvents_previous_document_cross_origin.sub.html.ini
testing/web-platform/meta/navigation-timing/nav2_test_unloadEvents_with_previous_document.html.ini
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -17,16 +17,17 @@
 #include "PerformanceResourceTiming.h"
 #include "PerformanceService.h"
 #include "PerformanceWorker.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/PerformanceBinding.h"
 #include "mozilla/dom/PerformanceEntryEvent.h"
 #include "mozilla/dom/PerformanceNavigationBinding.h"
 #include "mozilla/dom/PerformanceObserverBinding.h"
+#include "mozilla/dom/PerformanceNavigationTiming.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Preferences.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 
 #define PERFLOG(msg, ...) printf_stderr(msg, ##__VA_ARGS__)
 
 namespace mozilla {
--- a/dom/performance/Performance.h
+++ b/dom/performance/Performance.h
@@ -47,24 +47,24 @@ public:
                       nsITimedChannel* aChannel);
 
   static already_AddRefed<Performance>
   CreateForWorker(workers::WorkerPrivate* aWorkerPrivate);
 
   JSObject* WrapObject(JSContext *cx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
-  void GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval);
+  virtual void GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval);
 
-  void GetEntriesByType(const nsAString& aEntryType,
-                        nsTArray<RefPtr<PerformanceEntry>>& aRetval);
+  virtual void GetEntriesByType(const nsAString& aEntryType,
+                                nsTArray<RefPtr<PerformanceEntry>>& aRetval);
 
-  void GetEntriesByName(const nsAString& aName,
-                        const Optional<nsAString>& aEntryType,
-                        nsTArray<RefPtr<PerformanceEntry>>& aRetval);
+  virtual void GetEntriesByName(const nsAString& aName,
+                                const Optional<nsAString>& aEntryType,
+                                nsTArray<RefPtr<PerformanceEntry>>& aRetval);
 
   virtual void AddEntry(nsIHttpChannel* channel,
                         nsITimedChannel* timedChannel) = 0;
 
   void ClearResourceTimings();
 
   DOMHighResTimeStamp Now() const;
 
@@ -149,17 +149,17 @@ protected:
 
   void RunNotificationObserversTask();
   void QueueEntry(PerformanceEntry* aEntry);
 
   DOMHighResTimeStamp RoundTime(double aTime) const;
 
   nsTObserverArray<PerformanceObserver*> mObservers;
 
-private:
+protected:
   static const uint64_t kDefaultResourceTimingBufferSize = 150;
 
   // When kDefaultResourceTimingBufferSize is increased or removed, these should
   // be changed to use SegmentedVector
   AutoTArray<RefPtr<PerformanceEntry>, kDefaultResourceTimingBufferSize> mUserEntries;
   AutoTArray<RefPtr<PerformanceEntry>, kDefaultResourceTimingBufferSize> mResourceEntries;
 
   uint64_t mResourceTimingBufferSize;
--- a/dom/performance/PerformanceMainThread.cpp
+++ b/dom/performance/PerformanceMainThread.cpp
@@ -11,25 +11,27 @@
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PerformanceMainThread)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PerformanceMainThread,
                                                 Performance)
 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTiming,
-                                mNavigation)
+                                mNavigation,
+                                mDocEntry)
   tmp->mMozMemory = nullptr;
   mozilla::DropJSObjects(this);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PerformanceMainThread,
                                                   Performance)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTiming,
-                                    mNavigation)
+                                    mNavigation,
+                                    mDocEntry)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceMainThread,
                                                 Performance)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mMozMemory)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_ADDREF_INHERITED(PerformanceMainThread, Performance)
@@ -147,48 +149,17 @@ PerformanceMainThread::AddEntry(nsIHttpC
     // resource timing returns a relative timing (no offset).
     RefPtr<PerformanceTiming> performanceTiming =
         new PerformanceTiming(this, timedChannel, channel,
             0);
 
     // The PerformanceResourceTiming object will use the PerformanceTiming
     // object to get all the required timings.
     RefPtr<PerformanceResourceTiming> performanceEntry =
-      new PerformanceResourceTiming(performanceTiming, this, entryName);
-
-    nsAutoCString protocol;
-    // Can be an empty string.
-    Unused << channel->GetProtocolVersion(protocol);
-
-    // If this is a local fetch, nextHopProtocol should be set to empty string.
-    nsCOMPtr<nsICacheInfoChannel> cachedChannel = do_QueryInterface(channel);
-    if (cachedChannel) {
-      bool isFromCache;
-      if (NS_SUCCEEDED(cachedChannel->IsFromCache(&isFromCache))
-          && isFromCache) {
-        protocol.Truncate();
-      }
-    }
-
-    performanceEntry->SetNextHopProtocol(NS_ConvertUTF8toUTF16(protocol));
-
-    uint64_t encodedBodySize = 0;
-    Unused << channel->GetEncodedBodySize(&encodedBodySize);
-    performanceEntry->SetEncodedBodySize(encodedBodySize);
-
-    uint64_t transferSize = 0;
-    Unused << channel->GetTransferSize(&transferSize);
-    performanceEntry->SetTransferSize(transferSize);
-
-    uint64_t decodedBodySize = 0;
-    Unused << channel->GetDecodedBodySize(&decodedBodySize);
-    if (decodedBodySize == 0) {
-      decodedBodySize = encodedBodySize;
-    }
-    performanceEntry->SetDecodedBodySize(decodedBodySize);
+      new PerformanceResourceTiming(performanceTiming, this, entryName, channel);
 
     // If the initiator type had no valid value, then set it to the default
     // ("other") value.
     if (initiatorType.IsEmpty()) {
       initiatorType = NS_LITERAL_STRING("other");
     }
     performanceEntry->SetInitiatorType(initiatorType);
     InsertResourceEntry(performanceEntry);
@@ -333,10 +304,86 @@ PerformanceMainThread::CreationTimeStamp
 }
 
 DOMHighResTimeStamp
 PerformanceMainThread::CreationTime() const
 {
   return GetDOMTiming()->GetNavigationStart();
 }
 
+void
+PerformanceMainThread::EnsureDocEntry()
+{
+  if (!mDocEntry) {
+    nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
+    mDocEntry = new PerformanceNavigationTiming(Timing(), this,
+                                                httpChannel);
+  }
+}
+
+
+void
+PerformanceMainThread::GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval)
+{
+  // We return an empty list when 'privacy.resistFingerprinting' is on.
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    aRetval.Clear();
+    return;
+  }
+
+  aRetval = mResourceEntries;
+  aRetval.AppendElements(mUserEntries);
+
+  EnsureDocEntry();
+  if (mDocEntry) {
+    aRetval.AppendElement(mDocEntry);
+  }
+
+  aRetval.Sort(PerformanceEntryComparator());
+}
+
+void
+PerformanceMainThread::GetEntriesByType(const nsAString& aEntryType,
+                                        nsTArray<RefPtr<PerformanceEntry>>& aRetval)
+{
+  // We return an empty list when 'privacy.resistFingerprinting' is on.
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    aRetval.Clear();
+    return;
+  }
+
+  if (aEntryType.EqualsLiteral("navigation")) {
+    aRetval.Clear();
+    EnsureDocEntry();
+    if (mDocEntry) {
+      aRetval.AppendElement(mDocEntry);
+    }
+    return;
+  }
+
+  Performance::GetEntriesByType(aEntryType, aRetval);
+}
+
+void
+PerformanceMainThread::GetEntriesByName(const nsAString& aName,
+                                        const Optional<nsAString>& aEntryType,
+                                        nsTArray<RefPtr<PerformanceEntry>>& aRetval)
+{
+  // We return an empty list when 'privacy.resistFingerprinting' is on.
+  if (nsContentUtils::ShouldResistFingerprinting()) {
+    aRetval.Clear();
+    return;
+  }
+
+  if (aName.EqualsLiteral("document")) {
+    aRetval.Clear();
+    EnsureDocEntry();
+    if (mDocEntry) {
+      aRetval.AppendElement(mDocEntry);
+    }
+    return;
+  }
+
+  Performance::GetEntriesByName(aName, aEntryType, aRetval);
+}
+
 } // dom namespace
 } // mozilla namespace
--- a/dom/performance/PerformanceMainThread.h
+++ b/dom/performance/PerformanceMainThread.h
@@ -42,28 +42,39 @@ public:
     return mDOMTiming;
   }
 
   virtual nsITimedChannel* GetChannel() const override
   {
     return mChannel;
   }
 
+  // The GetEntries* methods need to be overriden in order to add the
+  // the document entry of type navigation.
+  virtual void GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval) override;
+  virtual void GetEntriesByType(const nsAString& aEntryType,
+                                nsTArray<RefPtr<PerformanceEntry>>& aRetval) override;
+  virtual void GetEntriesByName(const nsAString& aName,
+                                const Optional<nsAString>& aEntryType,
+                                nsTArray<RefPtr<PerformanceEntry>>& aRetval) override;
+
 protected:
   ~PerformanceMainThread();
 
   void InsertUserEntry(PerformanceEntry* aEntry) override;
 
   bool IsPerformanceTimingAttribute(const nsAString& aName) override;
 
   DOMHighResTimeStamp
   GetPerformanceTimingFromString(const nsAString& aTimingName) override;
 
   void DispatchBufferFullEvent() override;
+  void EnsureDocEntry();
 
+  RefPtr<PerformanceEntry> mDocEntry;
   RefPtr<nsDOMNavigationTiming> mDOMTiming;
   nsCOMPtr<nsITimedChannel> mChannel;
   RefPtr<PerformanceTiming> mTiming;
   RefPtr<PerformanceNavigation> mNavigation;
   JS::Heap<JSObject*> mMozMemory;
 };
 
 } // namespace dom
new file mode 100644
--- /dev/null
+++ b/dom/performance/PerformanceNavigationTiming.cpp
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/PerformanceNavigationTiming.h"
+#include "mozilla/dom/PerformanceNavigationTimingBinding.h"
+
+using namespace mozilla::dom;
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceNavigationTiming)
+NS_INTERFACE_MAP_END_INHERITING(PerformanceResourceTiming)
+
+NS_IMPL_ADDREF_INHERITED(PerformanceNavigationTiming, PerformanceResourceTiming)
+NS_IMPL_RELEASE_INHERITED(PerformanceNavigationTiming, PerformanceResourceTiming)
+
+JSObject*
+PerformanceNavigationTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return PerformanceNavigationTimingBinding::Wrap(aCx, this, aGivenProto);
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::UnloadEventStart()
+{
+  return mTiming->GetDOMTiming()->GetUnloadEventStart();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::UnloadEventEnd()
+{
+  return mTiming->GetDOMTiming()->GetUnloadEventEnd();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomInteractive()
+{
+  return mTiming->GetDOMTiming()->GetDomInteractive();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomContentLoadedEventStart()
+{
+  return mTiming->GetDOMTiming()->GetDomContentLoadedEventStart();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomContentLoadedEventEnd()
+{
+  return mTiming->GetDOMTiming()->GetDomContentLoadedEventEnd();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomComplete()
+{
+  return mTiming->GetDOMTiming()->GetDomComplete();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::LoadEventStart()
+{
+  return mTiming->GetDOMTiming()->GetLoadEventStart();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::LoadEventEnd() const
+{
+  return mTiming->GetDOMTiming()->GetLoadEventEnd();
+}
+
+NavigationType
+PerformanceNavigationTiming::Type()
+{
+  switch(mTiming->GetDOMTiming()->GetType()) {
+    case nsDOMNavigationTiming::TYPE_NAVIGATE:
+      return NavigationType::Navigate;
+      break;
+    case nsDOMNavigationTiming::TYPE_RELOAD:
+      return NavigationType::Reload;
+      break;
+    case nsDOMNavigationTiming::TYPE_BACK_FORWARD:
+      return NavigationType::Back_forward;
+      break;
+    default:
+      MOZ_CRASH(); // Should not happen
+      return NavigationType::Navigate;
+  }
+}
+
+uint16_t
+PerformanceNavigationTiming::RedirectCount()
+{
+  return mTiming->GetRedirectCount();
+}
new file mode 100644
--- /dev/null
+++ b/dom/performance/PerformanceNavigationTiming.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PerformanceNavigationTiming_h___
+#define mozilla_dom_PerformanceNavigationTiming_h___
+
+#include "nsCOMPtr.h"
+#include "nsIChannel.h"
+#include "nsITimedChannel.h"
+#include "mozilla/dom/PerformanceResourceTiming.h"
+#include "mozilla/dom/PerformanceNavigationTimingBinding.h"
+#include "nsIHttpChannel.h"
+
+namespace mozilla {
+namespace dom {
+
+// https://www.w3.org/TR/navigation-timing-2/#sec-PerformanceNavigationTiming
+class PerformanceNavigationTiming final
+  : public PerformanceResourceTiming
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  explicit PerformanceNavigationTiming(PerformanceTiming* aPerformanceTiming,
+                                       Performance* aPerformance,
+                                       nsIHttpChannel* aChannel)
+    : PerformanceResourceTiming(aPerformanceTiming, aPerformance,
+                                NS_LITERAL_STRING("document"), aChannel) {
+      SetEntryType(NS_LITERAL_STRING("navigation"));
+      SetInitiatorType(NS_LITERAL_STRING("navigation"));
+    }
+
+  DOMHighResTimeStamp Duration() const override
+  {
+    return LoadEventEnd() - StartTime();
+  }
+
+  DOMHighResTimeStamp StartTime() const override
+  {
+    return 0;
+  }
+
+  JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  DOMHighResTimeStamp UnloadEventStart();
+  DOMHighResTimeStamp UnloadEventEnd();
+
+  DOMHighResTimeStamp DomInteractive();
+  DOMHighResTimeStamp DomContentLoadedEventStart();
+  DOMHighResTimeStamp DomContentLoadedEventEnd();
+  DOMHighResTimeStamp DomComplete();
+  DOMHighResTimeStamp LoadEventStart();
+  DOMHighResTimeStamp LoadEventEnd() const;
+  NavigationType Type();
+  uint16_t RedirectCount();
+
+private:
+  ~PerformanceNavigationTiming() {}
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PerformanceNavigationTiming_h___
--- a/dom/performance/PerformanceResourceTiming.cpp
+++ b/dom/performance/PerformanceResourceTiming.cpp
@@ -20,24 +20,53 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceResourceTiming)
 NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry)
 
 NS_IMPL_ADDREF_INHERITED(PerformanceResourceTiming, PerformanceEntry)
 NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry)
 
 PerformanceResourceTiming::PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming,
                                                      Performance* aPerformance,
-                                                     const nsAString& aName)
+                                                     const nsAString& aName,
+                                                     nsIHttpChannel* aChannel)
 : PerformanceEntry(aPerformance->GetParentObject(), aName, NS_LITERAL_STRING("resource")),
   mTiming(aPerformanceTiming),
   mEncodedBodySize(0),
   mTransferSize(0),
   mDecodedBodySize(0)
 {
   MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
+  SetPropertiesFromChannel(aChannel);
+}
+
+void
+PerformanceResourceTiming::SetPropertiesFromChannel(nsIHttpChannel* aChannel)
+{
+  if (!aChannel) {
+    return;
+  }
+
+  nsAutoCString protocol;
+  Unused << aChannel->GetProtocolVersion(protocol);
+  SetNextHopProtocol(NS_ConvertUTF8toUTF16(protocol));
+
+  uint64_t encodedBodySize = 0;
+  Unused << aChannel->GetEncodedBodySize(&encodedBodySize);
+  SetEncodedBodySize(encodedBodySize);
+
+  uint64_t transferSize = 0;
+  Unused << aChannel->GetTransferSize(&transferSize);
+  SetTransferSize(transferSize);
+
+  uint64_t decodedBodySize = 0;
+  Unused << aChannel->GetDecodedBodySize(&decodedBodySize);
+  if (decodedBodySize == 0) {
+    decodedBodySize = encodedBodySize;
+  }
+  SetDecodedBodySize(decodedBodySize);
 }
 
 PerformanceResourceTiming::~PerformanceResourceTiming()
 {
 }
 
 DOMHighResTimeStamp
 PerformanceResourceTiming::StartTime() const
--- a/dom/performance/PerformanceResourceTiming.h
+++ b/dom/performance/PerformanceResourceTiming.h
@@ -13,29 +13,30 @@
 #include "Performance.h"
 #include "PerformanceEntry.h"
 #include "PerformanceTiming.h"
 
 namespace mozilla {
 namespace dom {
 
 // http://www.w3.org/TR/resource-timing/#performanceresourcetiming
-class PerformanceResourceTiming final : public PerformanceEntry
+class PerformanceResourceTiming : public PerformanceEntry
 {
 public:
   typedef mozilla::TimeStamp TimeStamp;
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
       PerformanceResourceTiming,
       PerformanceEntry)
 
   PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming,
                             Performance* aPerformance,
-                            const nsAString& aName);
+                            const nsAString& aName,
+                            nsIHttpChannel* aChannel = nullptr);
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 
   virtual DOMHighResTimeStamp StartTime() const override;
 
   virtual DOMHighResTimeStamp Duration() const override
   {
@@ -168,16 +169,17 @@ public:
     mDecodedBodySize = aDecodedBodySize;
   }
 
   size_t
   SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
 protected:
   virtual ~PerformanceResourceTiming();
+  void SetPropertiesFromChannel(nsIHttpChannel* aChannel);
 
   size_t
   SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
   nsString mInitiatorType;
   nsString mNextHopProtocol;
   RefPtr<PerformanceTiming> mTiming;
   uint64_t mEncodedBodySize;
--- a/dom/performance/moz.build
+++ b/dom/performance/moz.build
@@ -8,30 +8,32 @@ with Files("**"):
     BUG_COMPONENT = ("Core", "DOM")
 
 EXPORTS.mozilla.dom += [
     'Performance.h',
     'PerformanceEntry.h',
     'PerformanceMark.h',
     'PerformanceMeasure.h',
     'PerformanceNavigation.h',
+    'PerformanceNavigationTiming.h',
     'PerformanceObserver.h',
     'PerformanceObserverEntryList.h',
     'PerformanceResourceTiming.h',
     'PerformanceService.h',
     'PerformanceTiming.h',
 ]
 
 UNIFIED_SOURCES += [
     'Performance.cpp',
     'PerformanceEntry.cpp',
     'PerformanceMainThread.cpp',
     'PerformanceMark.cpp',
     'PerformanceMeasure.cpp',
     'PerformanceNavigation.cpp',
+    'PerformanceNavigationTiming.cpp',
     'PerformanceObserver.cpp',
     'PerformanceObserverEntryList.cpp',
     'PerformanceResourceTiming.cpp',
     'PerformanceService.cpp',
     'PerformanceTiming.cpp',
     'PerformanceWorker.cpp',
 ]
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PerformanceNavigationTiming.webidl
@@ -0,0 +1,33 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://www.w3.org/TR/navigation-timing-2/#sec-PerformanceNavigationTiming
+ *
+ * Copyright © 2016 W3C® (MIT, ERCIM, Keio, Beihang).
+ * W3C liability, trademark and document use rules apply.
+ */
+
+enum NavigationType {
+  "navigate",
+  "reload",
+  "back_forward",
+  "prerender"
+};
+
+interface PerformanceNavigationTiming : PerformanceResourceTiming {
+  readonly        attribute DOMHighResTimeStamp unloadEventStart;
+  readonly        attribute DOMHighResTimeStamp unloadEventEnd;
+  readonly        attribute DOMHighResTimeStamp domInteractive;
+  readonly        attribute DOMHighResTimeStamp domContentLoadedEventStart;
+  readonly        attribute DOMHighResTimeStamp domContentLoadedEventEnd;
+  readonly        attribute DOMHighResTimeStamp domComplete;
+  readonly        attribute DOMHighResTimeStamp loadEventStart;
+  readonly        attribute DOMHighResTimeStamp loadEventEnd;
+  readonly        attribute NavigationType      type;
+  readonly        attribute unsigned short      redirectCount;
+
+  jsonifier;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -734,16 +734,17 @@ WEBIDL_FILES = [
     'PaymentRequest.webidl',
     'PaymentRequestUpdateEvent.webidl',
     'PaymentResponse.webidl',
     'Performance.webidl',
     'PerformanceEntry.webidl',
     'PerformanceMark.webidl',
     'PerformanceMeasure.webidl',
     'PerformanceNavigation.webidl',
+    'PerformanceNavigationTiming.webidl',
     'PerformanceObserver.webidl',
     'PerformanceObserverEntryList.webidl',
     'PerformanceResourceTiming.webidl',
     'PerformanceTiming.webidl',
     'PeriodicWave.webidl',
     'Permissions.webidl',
     'PermissionStatus.webidl',
     'Plugin.webidl',
--- a/testing/web-platform/meta/navigation-timing/nav2_idlharness.html.ini
+++ b/testing/web-platform/meta/navigation-timing/nav2_idlharness.html.ini
@@ -1,50 +1,4 @@
 [nav2_idlharness.html]
   type: testharness
-  [PerformanceNavigationTiming interface: existence and properties of interface object]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface object length]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface object name]
-    expected: FAIL
-
   [PerformanceNavigationTiming interface: existence and properties of interface prototype object]
     expected: FAIL
-
-  [PerformanceNavigationTiming interface: existence and properties of interface prototype object's "constructor" property]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute unloadEventStart]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute unloadEventEnd]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute domInteractive]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute domContentLoadedEventStart]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute domContentLoadedEventEnd]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute domComplete]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute loadEventStart]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute loadEventEnd]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute type]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: attribute redirectCount]
-    expected: FAIL
-
-  [PerformanceNavigationTiming interface: operation toJSON()]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_document_open.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_document_open.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_document_replaced.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_document_replaced.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_frame_removed.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_frame_removed.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_instance_accessible_from_the_start.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_instance_accessible_from_the_start.html]
-  type: testharness
-  [PerformanceNavigationTiming instance exists with reasonable values.]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_navigate_within_document.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_navigate_within_document.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_navigation_type_backforward.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_navigation_type_backforward.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_navigation_type_reload.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_navigation_type_reload.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_redirect_server.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_redirect_server.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_redirect_xserver.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_redirect_xserver.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_unloadEvents_no_previous_document.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_unloadEvents_no_previous_document.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_unloadEvents_previous_document_cross_origin.sub.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_unloadEvents_previous_document_cross_origin.sub.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/nav2_test_unloadEvents_with_previous_document.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[nav2_test_unloadEvents_with_previous_document.html]
-  type: testharness
-  [Navigation Timing 2 WPT]
-    expected: FAIL
-