summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
Diffstat (limited to 'dom')
-rw-r--r--dom/base/nsContentUtils.cpp4
-rw-r--r--dom/base/nsContentUtils.h9
-rw-r--r--dom/base/nsDOMNavigationTiming.cpp138
-rw-r--r--dom/base/nsDOMNavigationTiming.h125
-rw-r--r--dom/base/nsGkAtomList.h1
-rw-r--r--dom/base/nsGlobalWindow.cpp20
-rw-r--r--dom/bindings/BindingUtils.cpp20
-rw-r--r--dom/bindings/Codegen.py14
-rw-r--r--dom/bindings/ErrorResult.h2
-rwxr-xr-xdom/console/Console.cpp5
-rw-r--r--dom/console/Console.h10
-rwxr-xr-xdom/events/Event.cpp7
-rw-r--r--dom/events/EventNameList.h4
-rw-r--r--dom/events/EventStateManager.cpp66
-rw-r--r--dom/events/EventStateManager.h10
-rw-r--r--dom/events/WheelHandlingHelper.cpp1
-rw-r--r--dom/events/test/mochitest.ini1
-rw-r--r--dom/events/test/test_bug1304044.html133
-rw-r--r--dom/events/test/test_eventTimeStamp.html36
-rw-r--r--dom/media/MediaStreamTrack.cpp12
-rwxr-xr-xdom/performance/Performance.cpp49
-rw-r--r--dom/performance/Performance.h36
-rw-r--r--dom/performance/PerformanceEntry.h21
-rw-r--r--dom/performance/PerformanceMainThread.cpp99
-rw-r--r--dom/performance/PerformanceMainThread.h21
-rw-r--r--dom/performance/PerformanceNavigationTiming.cpp96
-rw-r--r--dom/performance/PerformanceNavigationTiming.h71
-rw-r--r--dom/performance/PerformanceObserver.cpp14
-rw-r--r--dom/performance/PerformanceObserverEntryList.cpp15
-rw-r--r--dom/performance/PerformanceResourceTiming.cpp49
-rw-r--r--dom/performance/PerformanceResourceTiming.h12
-rw-r--r--dom/performance/PerformanceService.cpp46
-rw-r--r--dom/performance/PerformanceService.h48
-rwxr-xr-xdom/performance/PerformanceTiming.cpp71
-rwxr-xr-xdom/performance/PerformanceTiming.h18
-rw-r--r--dom/performance/PerformanceWorker.cpp35
-rw-r--r--dom/performance/PerformanceWorker.h14
-rw-r--r--dom/performance/moz.build4
-rw-r--r--dom/performance/tests/mochitest.ini3
-rw-r--r--dom/performance/tests/performance_observer.html74
-rw-r--r--dom/performance/tests/test_performance_observer.html52
-rw-r--r--dom/performance/tests/test_performance_user_timing.js21
-rw-r--r--dom/performance/tests/test_timeOrigin.html68
-rw-r--r--dom/performance/tests/test_worker_observer.html13
-rw-r--r--dom/performance/tests/worker_performance_observer.html32
-rw-r--r--dom/plugins/base/nsPluginInstanceOwner.cpp3
-rw-r--r--dom/tests/mochitest/general/test_interfaces.html6
-rw-r--r--dom/webidl/EventHandler.webidl1
-rw-r--r--dom/webidl/Performance.webidl3
-rw-r--r--dom/webidl/PerformanceNavigationTiming.webidl33
-rw-r--r--dom/webidl/PerformanceObserver.webidl1
-rw-r--r--dom/webidl/PerformanceResourceTiming.webidl8
-rw-r--r--dom/webidl/PerformanceTiming.webidl6
-rw-r--r--dom/webidl/moz.build1
-rw-r--r--dom/workers/ServiceWorkerEvents.cpp10
-rw-r--r--dom/workers/ServiceWorkerPrivate.cpp45
-rw-r--r--dom/workers/ServiceWorkerPrivate.h1
-rw-r--r--dom/workers/WorkerPrivate.cpp14
-rw-r--r--dom/workers/WorkerPrivate.h13
-rw-r--r--dom/workers/test/serviceworkers/chrome.ini3
-rw-r--r--dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html168
-rw-r--r--dom/workers/test/serviceworkers/test_serviceworker_interfaces.js4
-rw-r--r--dom/workers/test/test_worker_interfaces.js4
-rw-r--r--dom/xslt/xpath/txXPCOMExtensionFunction.cpp2
64 files changed, 1395 insertions, 531 deletions
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index ef87a250e..bc8cea35a 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -281,6 +281,7 @@ bool nsContentUtils::sIsCutCopyAllowed = true;
bool nsContentUtils::sIsFrameTimingPrefEnabled = false;
bool nsContentUtils::sIsPerformanceTimingEnabled = false;
bool nsContentUtils::sIsResourceTimingEnabled = false;
+bool nsContentUtils::sIsPerformanceNavigationTimingEnabled = false;
bool nsContentUtils::sIsUserTimingLoggingEnabled = false;
bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
bool nsContentUtils::sEncodeDecodeURLHash = false;
@@ -571,6 +572,9 @@ nsContentUtils::Init()
Preferences::AddBoolVarCache(&sIsResourceTimingEnabled,
"dom.enable_resource_timing", true);
+ Preferences::AddBoolVarCache(&sIsPerformanceNavigationTimingEnabled,
+ "dom.enable_performance_navigation_timing", true);
+
Preferences::AddBoolVarCache(&sIsUserTimingLoggingEnabled,
"dom.performance.enable_user_timing_logging", false);
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 0932f451e..9ae6d2155 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2033,6 +2033,14 @@ public:
}
/*
+ * Returns true if the performance timing APIs are enabled.
+ */
+ static bool IsPerformanceNavigationTimingEnabled()
+ {
+ return sIsPerformanceNavigationTimingEnabled;
+ }
+
+ /*
* Returns true if notification should be sent for peformance timing events.
*/
static bool SendPerformanceTimingNotifications()
@@ -2825,6 +2833,7 @@ private:
static uint32_t sHandlingInputTimeout;
static bool sIsPerformanceTimingEnabled;
static bool sIsResourceTimingEnabled;
+ static bool sIsPerformanceNavigationTimingEnabled;
static bool sIsUserTimingLoggingEnabled;
static bool sIsFrameTimingPrefEnabled;
static bool sIsExperimentalAutocompleteEnabled;
diff --git a/dom/base/nsDOMNavigationTiming.cpp b/dom/base/nsDOMNavigationTiming.cpp
index 31b2932fb..32ce8a8cb 100644
--- a/dom/base/nsDOMNavigationTiming.cpp
+++ b/dom/base/nsDOMNavigationTiming.cpp
@@ -15,6 +15,9 @@
#include "nsPrintfCString.h"
#include "mozilla/dom/PerformanceNavigation.h"
#include "mozilla/TimeStamp.h"
+#include "mozilla/Telemetry.h"
+
+using namespace mozilla;
nsDOMNavigationTiming::nsDOMNavigationTiming()
{
@@ -30,47 +33,36 @@ nsDOMNavigationTiming::Clear()
{
mNavigationType = TYPE_RESERVED;
mNavigationStartHighRes = 0;
- mBeforeUnloadStart = 0;
- mUnloadStart = 0;
- mUnloadEnd = 0;
- mLoadEventStart = 0;
- mLoadEventEnd = 0;
- mDOMLoading = 0;
- mDOMInteractive = 0;
- mDOMContentLoadedEventStart = 0;
- mDOMContentLoadedEventEnd = 0;
- mDOMComplete = 0;
-
- mLoadEventStartSet = false;
- mLoadEventEndSet = false;
- mDOMLoadingSet = false;
- mDOMInteractiveSet = false;
- mDOMContentLoadedEventStartSet = false;
- mDOMContentLoadedEventEndSet = false;
- mDOMCompleteSet = false;
+ mBeforeUnloadStart = TimeStamp();
+ mUnloadStart = TimeStamp();
+ mUnloadEnd = TimeStamp();
+ mLoadEventStart = TimeStamp();
+ mLoadEventEnd = TimeStamp();
+ mDOMLoading = TimeStamp();
+ mDOMInteractive = TimeStamp();
+ mDOMContentLoadedEventStart = TimeStamp();
+ mDOMContentLoadedEventEnd = TimeStamp();
+ mDOMComplete = TimeStamp();
+
mDocShellHasBeenActiveSinceNavigationStart = false;
}
DOMTimeMilliSec
-nsDOMNavigationTiming::TimeStampToDOM(mozilla::TimeStamp aStamp) const
+nsDOMNavigationTiming::TimeStampToDOM(TimeStamp aStamp) const
{
if (aStamp.IsNull()) {
return 0;
}
- mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp;
- return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds());
-}
-DOMTimeMilliSec nsDOMNavigationTiming::DurationFromStart()
-{
- return TimeStampToDOM(mozilla::TimeStamp::Now());
+ TimeDuration duration = aStamp - mNavigationStart;
+ return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds());
}
void
nsDOMNavigationTiming::NotifyNavigationStart(DocShellState aDocShellState)
{
mNavigationStartHighRes = (double)PR_Now() / PR_USEC_PER_MSEC;
- mNavigationStartTimeStamp = mozilla::TimeStamp::Now();
+ mNavigationStart = TimeStamp::Now();
mDocShellHasBeenActiveSinceNavigationStart = (aDocShellState == DocShellState::eActive);
}
@@ -86,7 +78,7 @@ nsDOMNavigationTiming::NotifyFetchStart(nsIURI* aURI, Type aNavigationType)
void
nsDOMNavigationTiming::NotifyBeforeUnload()
{
- mBeforeUnloadStart = DurationFromStart();
+ mBeforeUnloadStart = TimeStamp::Now();
}
void
@@ -99,105 +91,107 @@ nsDOMNavigationTiming::NotifyUnloadAccepted(nsIURI* aOldURI)
void
nsDOMNavigationTiming::NotifyUnloadEventStart()
{
- mUnloadStart = DurationFromStart();
+ mUnloadStart = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyUnloadEventEnd()
{
- mUnloadEnd = DurationFromStart();
+ mUnloadEnd = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyLoadEventStart()
{
- if (!mLoadEventStartSet) {
- mLoadEventStart = DurationFromStart();
- mLoadEventStartSet = true;
+ if (!mLoadEventStart.IsNull()) {
+ return;
}
+ mLoadEventStart = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyLoadEventEnd()
{
- if (!mLoadEventEndSet) {
- mLoadEventEnd = DurationFromStart();
- mLoadEventEndSet = true;
+ if (!mLoadEventEnd.IsNull()) {
+ return;
}
+ mLoadEventEnd = TimeStamp::Now();
}
void
-nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue)
+nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, TimeStamp aValue)
{
- if (!mDOMLoadingSet) {
- mLoadedURI = aURI;
- mDOMLoading = TimeStampToDOM(aValue);
- mDOMLoadingSet = true;
+ if (!mDOMLoading.IsNull()) {
+ return;
}
+ mLoadedURI = aURI;
+ mDOMLoading = aValue;
}
void
nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI)
{
- if (!mDOMLoadingSet) {
- mLoadedURI = aURI;
- mDOMLoading = DurationFromStart();
- mDOMLoadingSet = true;
+ if (!mDOMLoading.IsNull()) {
+ return;
}
+ mLoadedURI = aURI;
+ mDOMLoading = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI)
{
- if (!mDOMInteractiveSet) {
- mLoadedURI = aURI;
- mDOMInteractive = DurationFromStart();
- mDOMInteractiveSet = true;
+ if (!mDOMInteractive.IsNull()) {
+ return;
}
+ mLoadedURI = aURI;
+ mDOMInteractive = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI)
{
- if (!mDOMCompleteSet) {
- mLoadedURI = aURI;
- mDOMComplete = DurationFromStart();
- mDOMCompleteSet = true;
+ if (!mDOMComplete.IsNull()) {
+ return;
}
+ mLoadedURI = aURI;
+ mDOMComplete = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI)
{
- if (!mDOMContentLoadedEventStartSet) {
- mLoadedURI = aURI;
- mDOMContentLoadedEventStart = DurationFromStart();
- mDOMContentLoadedEventStartSet = true;
+ if (!mDOMContentLoadedEventStart.IsNull()) {
+ return;
}
+
+ mLoadedURI = aURI;
+ mDOMContentLoadedEventStart = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI)
{
- if (!mDOMContentLoadedEventEndSet) {
- mLoadedURI = aURI;
- mDOMContentLoadedEventEnd = DurationFromStart();
- mDOMContentLoadedEventEndSet = true;
+ if (!mDOMContentLoadedEventEnd.IsNull()) {
+ return;
}
+
+ mLoadedURI = aURI;
+ mDOMContentLoadedEventEnd = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument()
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!mNavigationStartTimeStamp.IsNull());
+ MOZ_ASSERT(!mNavigationStart.IsNull());
- if (!mNonBlankPaintTimeStamp.IsNull()) {
+ if (!mNonBlankPaint.IsNull()) {
return;
}
- mNonBlankPaintTimeStamp = TimeStamp::Now();
- TimeDuration elapsed = mNonBlankPaintTimeStamp - mNavigationStartTimeStamp;
+ mNonBlankPaint = TimeStamp::Now();
+ TimeDuration elapsed = mNonBlankPaint - mNavigationStart;
if (profiler_is_active()) {
nsAutoCString spec;
@@ -212,8 +206,8 @@ nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument()
if (mDocShellHasBeenActiveSinceNavigationStart) {
Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS,
- mNavigationStartTimeStamp,
- mNonBlankPaintTimeStamp);
+ mNavigationStart,
+ mNonBlankPaint);
}
}
@@ -224,24 +218,24 @@ nsDOMNavigationTiming::NotifyDocShellStateChanged(DocShellState aDocShellState)
(aDocShellState == DocShellState::eActive);
}
-DOMTimeMilliSec
-nsDOMNavigationTiming::GetUnloadEventStart()
+mozilla::TimeStamp
+nsDOMNavigationTiming::GetUnloadEventStartTimeStamp() const
{
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false);
if (NS_SUCCEEDED(rv)) {
return mUnloadStart;
}
- return 0;
+ return mozilla::TimeStamp();
}
-DOMTimeMilliSec
-nsDOMNavigationTiming::GetUnloadEventEnd()
+mozilla::TimeStamp
+nsDOMNavigationTiming::GetUnloadEventEndTimeStamp() const
{
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false);
if (NS_SUCCEEDED(rv)) {
return mUnloadEnd;
}
- return 0;
+ return mozilla::TimeStamp();
}
diff --git a/dom/base/nsDOMNavigationTiming.h b/dom/base/nsDOMNavigationTiming.h
index 9babece96..3be2527ca 100644
--- a/dom/base/nsDOMNavigationTiming.h
+++ b/dom/base/nsDOMNavigationTiming.h
@@ -47,38 +47,91 @@ public:
mozilla::TimeStamp GetNavigationStartTimeStamp() const
{
- return mNavigationStartTimeStamp;
+ return mNavigationStart;
+ }
+
+ DOMTimeMilliSec GetUnloadEventStart()
+ {
+ return TimeStampToDOM(GetUnloadEventStartTimeStamp());
+ }
+
+ DOMTimeMilliSec GetUnloadEventEnd()
+ {
+ return TimeStampToDOM(GetUnloadEventEndTimeStamp());
}
- DOMTimeMilliSec GetUnloadEventStart();
- DOMTimeMilliSec GetUnloadEventEnd();
DOMTimeMilliSec GetDomLoading() const
{
- return mDOMLoading;
+ return TimeStampToDOM(mDOMLoading);
}
DOMTimeMilliSec GetDomInteractive() const
{
- return mDOMInteractive;
+ return TimeStampToDOM(mDOMInteractive);
}
DOMTimeMilliSec GetDomContentLoadedEventStart() const
{
- return mDOMContentLoadedEventStart;
+ return TimeStampToDOM(mDOMContentLoadedEventStart);
}
DOMTimeMilliSec GetDomContentLoadedEventEnd() const
{
- return mDOMContentLoadedEventEnd;
+ return TimeStampToDOM(mDOMContentLoadedEventEnd);
}
DOMTimeMilliSec GetDomComplete() const
{
- return mDOMComplete;
+ return TimeStampToDOM(mDOMComplete);
}
DOMTimeMilliSec GetLoadEventStart() const
{
- return mLoadEventStart;
+ return TimeStampToDOM(mLoadEventStart);
}
DOMTimeMilliSec GetLoadEventEnd() const
{
- return mLoadEventEnd;
+ return TimeStampToDOM(mLoadEventEnd);
+ }
+ DOMTimeMilliSec GetTimeToNonBlankPaint() const
+ {
+ return TimeStampToDOM(mNonBlankPaint);
+ }
+
+ DOMHighResTimeStamp GetUnloadEventStartHighRes()
+ {
+ mozilla::TimeStamp stamp = GetUnloadEventStartTimeStamp();
+ if (stamp.IsNull()) {
+ return 0;
+ }
+ return TimeStampToDOMHighRes(stamp);
+ }
+ DOMHighResTimeStamp GetUnloadEventEndHighRes()
+ {
+ mozilla::TimeStamp stamp = GetUnloadEventEndTimeStamp();
+ if (stamp.IsNull()) {
+ return 0;
+ }
+ return TimeStampToDOMHighRes(stamp);
+ }
+ DOMHighResTimeStamp GetDomInteractiveHighRes() const
+ {
+ return TimeStampToDOMHighRes(mDOMInteractive);
+ }
+ DOMHighResTimeStamp GetDomContentLoadedEventStartHighRes() const
+ {
+ return TimeStampToDOMHighRes(mDOMContentLoadedEventStart);
+ }
+ DOMHighResTimeStamp GetDomContentLoadedEventEndHighRes() const
+ {
+ return TimeStampToDOMHighRes(mDOMContentLoadedEventEnd);
+ }
+ DOMHighResTimeStamp GetDomCompleteHighRes() const
+ {
+ return TimeStampToDOMHighRes(mDOMComplete);
+ }
+ DOMHighResTimeStamp GetLoadEventStartHighRes() const
+ {
+ return TimeStampToDOMHighRes(mLoadEventStart);
+ }
+ DOMHighResTimeStamp GetLoadEventEndHighRes() const
+ {
+ return TimeStampToDOMHighRes(mLoadEventEnd);
}
enum class DocShellState : uint8_t {
@@ -108,9 +161,13 @@ public:
DOMTimeMilliSec TimeStampToDOM(mozilla::TimeStamp aStamp) const;
- inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp)
+ inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp) const
{
- mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp;
+ MOZ_ASSERT(!aStamp.IsNull(), "The timestamp should not be null");
+ if (aStamp.IsNull()) {
+ return 0;
+ }
+ mozilla::TimeDuration duration = aStamp - mNavigationStart;
return duration.ToMilliseconds();
}
@@ -120,37 +177,29 @@ private:
void Clear();
+ mozilla::TimeStamp GetUnloadEventStartTimeStamp() const;
+ mozilla::TimeStamp GetUnloadEventEndTimeStamp() const;
+
nsCOMPtr<nsIURI> mUnloadedURI;
nsCOMPtr<nsIURI> mLoadedURI;
Type mNavigationType;
DOMHighResTimeStamp mNavigationStartHighRes;
- mozilla::TimeStamp mNavigationStartTimeStamp;
- mozilla::TimeStamp mNonBlankPaintTimeStamp;
- DOMTimeMilliSec DurationFromStart();
-
- DOMTimeMilliSec mBeforeUnloadStart;
- DOMTimeMilliSec mUnloadStart;
- DOMTimeMilliSec mUnloadEnd;
- DOMTimeMilliSec mLoadEventStart;
- DOMTimeMilliSec mLoadEventEnd;
-
- DOMTimeMilliSec mDOMLoading;
- DOMTimeMilliSec mDOMInteractive;
- DOMTimeMilliSec mDOMContentLoadedEventStart;
- DOMTimeMilliSec mDOMContentLoadedEventEnd;
- DOMTimeMilliSec mDOMComplete;
-
- // Booleans to keep track of what things we've already been notified
- // about. We don't update those once we've been notified about them
- // once.
- bool mLoadEventStartSet : 1;
- bool mLoadEventEndSet : 1;
- bool mDOMLoadingSet : 1;
- bool mDOMInteractiveSet : 1;
- bool mDOMContentLoadedEventStartSet : 1;
- bool mDOMContentLoadedEventEndSet : 1;
- bool mDOMCompleteSet : 1;
+ mozilla::TimeStamp mNavigationStart;
+ mozilla::TimeStamp mNonBlankPaint;
+
+ mozilla::TimeStamp mBeforeUnloadStart;
+ mozilla::TimeStamp mUnloadStart;
+ mozilla::TimeStamp mUnloadEnd;
+ mozilla::TimeStamp mLoadEventStart;
+ mozilla::TimeStamp mLoadEventEnd;
+
+ mozilla::TimeStamp mDOMLoading;
+ mozilla::TimeStamp mDOMInteractive;
+ mozilla::TimeStamp mDOMContentLoadedEventStart;
+ mozilla::TimeStamp mDOMContentLoadedEventEnd;
+ mozilla::TimeStamp mDOMComplete;
+
bool mDocShellHasBeenActiveSinceNavigationStart : 1;
};
diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h
index e4ae7ede8..aa4ef2ca3 100644
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -704,6 +704,7 @@ GK_ATOM(onattributechanged, "onattributechanged")
GK_ATOM(onattributereadreq, "onattributereadreq")
GK_ATOM(onattributewritereq, "onattributewritereq")
GK_ATOM(onaudioprocess, "onaudioprocess")
+GK_ATOM(onauxclick, "onauxclick")
GK_ATOM(onbeforecopy, "onbeforecopy")
GK_ATOM(onbeforecut, "onbeforecut")
GK_ATOM(onbeforepaste, "onbeforepaste")
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 3d5c44a78..738703ef1 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3124,8 +3124,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
newInnerWindow->mPerformance =
Performance::CreateForMainThread(newInnerWindow->AsInner(),
currentInner->mPerformance->GetDOMTiming(),
- currentInner->mPerformance->GetChannel(),
- currentInner->mPerformance->GetParentPerformance());
+ currentInner->mPerformance->GetChannel());
}
}
@@ -4339,22 +4338,7 @@ nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded()
timedChannel = nullptr;
}
if (timing) {
- // If we are dealing with an iframe, we will need the parent's performance
- // object (so we can add the iframe as a resource of that page).
- Performance* parentPerformance = nullptr;
- nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetScriptableParentOrNull();
- if (parentWindow) {
- nsPIDOMWindowInner* parentInnerWindow = nullptr;
- if (parentWindow) {
- parentInnerWindow = parentWindow->GetCurrentInnerWindow();
- }
- if (parentInnerWindow) {
- parentPerformance = parentInnerWindow->GetPerformance();
- }
- }
- mPerformance =
- Performance::CreateForMainThread(this, timing, timedChannel,
- parentPerformance);
+ mPerformance = Performance::CreateForMainThread(this, timing, timedChannel);
}
}
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index 33f5f7a44..7056658a7 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -259,8 +259,8 @@ TErrorResult<CleanupPolicy>::ThrowJSException(JSContext* cx, JS::Handle<JS::Valu
// Make sure mJSException is initialized _before_ we try to root it. But
// don't set it to exn yet, because we don't want to do that until after we
// root.
- mJSException.setUndefined();
- if (!js::AddRawValueRoot(cx, &mJSException, "TErrorResult::mJSException")) {
+ mJSException.asValueRef().setUndefined();
+ if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
// Don't use NS_ERROR_DOM_JS_EXCEPTION, because that indicates we have
// in fact rooted mJSException.
mResult = NS_ERROR_OUT_OF_MEMORY;
@@ -289,7 +289,7 @@ TErrorResult<CleanupPolicy>::SetPendingJSException(JSContext* cx)
mJSException = exception;
// If JS_WrapValue failed, not much we can do about it... No matter
// what, go ahead and unroot mJSException.
- js::RemoveRawValueRoot(cx, &mJSException);
+ js::RemoveRawValueRoot(cx, &mJSException.asValueRef());
mResult = NS_OK;
#ifdef DEBUG
@@ -395,8 +395,8 @@ TErrorResult<CleanupPolicy>::ClearUnionData()
if (IsJSException()) {
JSContext* cx = dom::danger::GetJSContext();
MOZ_ASSERT(cx);
- mJSException.setUndefined();
- js::RemoveRawValueRoot(cx, &mJSException);
+ mJSException.asValueRef().setUndefined();
+ js::RemoveRawValueRoot(cx, &mJSException.asValueRef());
#ifdef DEBUG
mUnionState = HasNothing;
#endif // DEBUG
@@ -439,13 +439,13 @@ TErrorResult<CleanupPolicy>::operator=(TErrorResult<CleanupPolicy>&& aRHS)
} else if (aRHS.IsJSException()) {
JSContext* cx = dom::danger::GetJSContext();
MOZ_ASSERT(cx);
- mJSException.setUndefined();
- if (!js::AddRawValueRoot(cx, &mJSException, "TErrorResult::mJSException")) {
+ mJSException.asValueRef().setUndefined();
+ if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
MOZ_CRASH("Could not root mJSException, we're about to OOM");
}
mJSException = aRHS.mJSException;
- aRHS.mJSException.setUndefined();
- js::RemoveRawValueRoot(cx, &aRHS.mJSException);
+ aRHS.mJSException.asValueRef().setUndefined();
+ js::RemoveRawValueRoot(cx, &aRHS.mJSException.asValueRef());
} else if (aRHS.IsDOMException()) {
mDOMExceptionInfo = aRHS.mDOMExceptionInfo;
aRHS.mDOMExceptionInfo = nullptr;
@@ -497,7 +497,7 @@ TErrorResult<CleanupPolicy>::CloneTo(TErrorResult& aRv) const
aRv.mUnionState = HasJSException;
#endif
JSContext* cx = dom::danger::GetJSContext();
- JS::Rooted<JS::Value> exception(cx, mJSException);
+ JS::Rooted<JS::Value> exception(cx, mJSException.asValueRef());
aRv.ThrowJSException(cx, exception);
}
}
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index 3174c37dd..7a6668687 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1069,6 +1069,20 @@ class CGHeaders(CGWrapper):
if parent:
ancestors.append(parent)
interfaceDeps.extend(ancestors)
+
+ # Include parent interface headers needed for jsonifier code.
+ jsonInterfaceParents = []
+ for desc in descriptors:
+ if not desc.operations['Jsonifier']:
+ continue
+ parent = desc.interface.parent
+ while parent:
+ parentDesc = desc.getDescriptor(parent.identifier.name)
+ if parentDesc.operations['Jsonifier']:
+ jsonInterfaceParents.append(parentDesc.interface)
+ parent = parent.parent
+ interfaceDeps.extend(jsonInterfaceParents)
+
bindingIncludes = set(self.getDeclarationFilename(d) for d in interfaceDeps)
# Grab all the implementation declaration files we need.
diff --git a/dom/bindings/ErrorResult.h b/dom/bindings/ErrorResult.h
index c45e7ea3b..7c3fc9e2f 100644
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -461,7 +461,7 @@ private:
// (and deallocated) by SetPendingDOMException.
union {
Message* mMessage; // valid when IsErrorWithMessage()
- JS::Value mJSException; // valid when IsJSException()
+ JS::UninitializedValue mJSException; // valid when IsJSException()
DOMExceptionInfo* mDOMExceptionInfo; // valid when IsDOMException()
};
diff --git a/dom/console/Console.cpp b/dom/console/Console.cpp
index 79e3eadc5..ff5a92167 100755
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -1336,10 +1336,7 @@ Console::MethodInternal(JSContext* aCx, MethodName aMethodName,
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
- TimeDuration duration =
- mozilla::TimeStamp::Now() - workerPrivate->NowBaseTimeStamp();
-
- monotonicTimer = TimerClamping::ReduceMsTimeValue(duration.ToMilliseconds());
+ monotonicTimer = workerPrivate->TimeStampToDOMHighRes(TimeStamp::Now());
}
}
diff --git a/dom/console/Console.h b/dom/console/Console.h
index b334d79f9..2f375c8eb 100644
--- a/dom/console/Console.h
+++ b/dom/console/Console.h
@@ -258,9 +258,8 @@ private:
// the max number of timers is reached.
// * aCx - the JSContext rooting aName.
// * aName - this is (should be) the name of the timer as JS::Value.
- // * aTimestamp - the monotonicTimer for this context (taken from
- // window->performance.now() or from Now() -
- // workerPrivate->NowBaseTimeStamp() in workers.
+ // * aTimestamp - the monotonicTimer for this context taken from
+ // performance.now().
// * aTimerLabel - This label will be populated with the aName converted to a
// string.
// * aTimerValue - the StartTimer value stored into (or taken from)
@@ -290,9 +289,8 @@ private:
// the aName timer doesn't exist in the mTimerRegistry.
// * aCx - the JSContext rooting aName.
// * aName - this is (should be) the name of the timer as JS::Value.
- // * aTimestamp - the monotonicTimer for this context (taken from
- // window->performance.now() or from Now() -
- // workerPrivate->NowBaseTimeStamp() in workers.
+ // * aTimestamp - the monotonicTimer for this context taken from
+ // performance.now().
// * aTimerLabel - This label will be populated with the aName converted to a
// string.
// * aTimerDuration - the difference between aTimestamp and when the timer
diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp
index 7e19cd74d..4b9776c0a 100755
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -1146,16 +1146,11 @@ Event::TimeStampImpl() const
return perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp);
}
- // For dedicated workers, we should make times relative to the navigation
- // start of the document that created the worker, which is the same as the
- // timebase for performance.now().
workers::WorkerPrivate* workerPrivate =
workers::GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
- TimeDuration duration =
- mEvent->mTimeStamp - workerPrivate->NowBaseTimeStamp();
- return duration.ToMilliseconds();
+ return workerPrivate->TimeStampToDOMHighRes(mEvent->mTimeStamp);
}
bool
diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h
index ba2427623..891035c43 100644
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -164,6 +164,10 @@ EVENT(change,
eFormChange,
EventNameType_HTMLXUL,
eBasicEventClass)
+EVENT(auxclick,
+ eMouseAuxClick,
+ EventNameType_All,
+ eMouseEventClass)
EVENT(click,
eMouseClick,
EventNameType_All,
diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp
index c6b304183..7bbfe21b7 100644
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -492,6 +492,7 @@ IsMessageMouseUserActivity(EventMessage aMessage)
return aMessage == eMouseMove ||
aMessage == eMouseUp ||
aMessage == eMouseDown ||
+ aMessage == eMouseAuxClick ||
aMessage == eMouseDoubleClick ||
aMessage == eMouseClick ||
aMessage == eMouseActivate ||
@@ -4633,6 +4634,32 @@ EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
}
nsresult
+EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
+ nsEventStatus* aStatus,
+ EventMessage aMessage,
+ nsIPresShell* aPresShell,
+ nsIContent* aMouseTarget,
+ nsWeakFrame aCurrentTarget,
+ bool aNoContentDispatch)
+{
+ WidgetMouseEvent event(aEvent->IsTrusted(), aMessage,
+ aEvent->mWidget, WidgetMouseEvent::eReal);
+
+ event.mRefPoint = aEvent->mRefPoint;
+ event.mClickCount = aEvent->mClickCount;
+ event.mModifiers = aEvent->mModifiers;
+ event.buttons = aEvent->buttons;
+ event.mTime = aEvent->mTime;
+ event.mTimeStamp = aEvent->mTimeStamp;
+ event.mFlags.mNoContentDispatch = aNoContentDispatch;
+ event.button = aEvent->button;
+ event.inputSource = aEvent->inputSource;
+
+ return aPresShell->HandleEventWithTarget(&event, aCurrentTarget,
+ aMouseTarget, aStatus);
+}
+
+nsresult
EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
nsEventStatus* aStatus)
{
@@ -4651,17 +4678,7 @@ EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
(aEvent->button == WidgetMouseEvent::eMiddleButton ||
aEvent->button == WidgetMouseEvent::eRightButton);
- WidgetMouseEvent event(aEvent->IsTrusted(), eMouseClick,
- aEvent->mWidget, WidgetMouseEvent::eReal);
- event.mRefPoint = aEvent->mRefPoint;
- event.mClickCount = aEvent->mClickCount;
- event.mModifiers = aEvent->mModifiers;
- event.buttons = aEvent->buttons;
- event.mTime = aEvent->mTime;
- event.mTimeStamp = aEvent->mTimeStamp;
- event.mFlags.mNoContentDispatch = notDispatchToContents;
- event.button = aEvent->button;
- event.inputSource = aEvent->inputSource;
+ bool fireAuxClick = notDispatchToContents;
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
if (presShell) {
@@ -4680,23 +4697,22 @@ EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
// HandleEvent clears out mCurrentTarget which we might need again
nsWeakFrame currentTarget = mCurrentTarget;
- ret = presShell->HandleEventWithTarget(&event, currentTarget,
- mouseContent, aStatus);
+ ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseClick,
+ presShell, mouseContent, currentTarget,
+ notDispatchToContents);
+
if (NS_SUCCEEDED(ret) && aEvent->mClickCount == 2 &&
mouseContent && mouseContent->IsInComposedDoc()) {
//fire double click
- WidgetMouseEvent event2(aEvent->IsTrusted(), eMouseDoubleClick,
- aEvent->mWidget, WidgetMouseEvent::eReal);
- event2.mRefPoint = aEvent->mRefPoint;
- event2.mClickCount = aEvent->mClickCount;
- event2.mModifiers = aEvent->mModifiers;
- event2.buttons = aEvent->buttons;
- event2.mFlags.mNoContentDispatch = notDispatchToContents;
- event2.button = aEvent->button;
- event2.inputSource = aEvent->inputSource;
-
- ret = presShell->HandleEventWithTarget(&event2, currentTarget,
- mouseContent, aStatus);
+ ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseDoubleClick,
+ presShell, mouseContent, currentTarget,
+ notDispatchToContents);
+ }
+ if (NS_SUCCEEDED(ret) && mouseContent && fireAuxClick &&
+ mouseContent->IsInComposedDoc()) {
+ ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseAuxClick,
+ presShell, mouseContent, currentTarget,
+ false);
}
}
}
diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h
index 49ecf0586..d0461e7fa 100644
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -415,6 +415,13 @@ protected:
*/
void UpdateDragDataTransfer(WidgetDragEvent* dragEvent);
+ static nsresult InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
+ nsEventStatus* aStatus,
+ EventMessage aMessage,
+ nsIPresShell* aPresShell,
+ nsIContent* aMouseTarget,
+ nsWeakFrame aCurrentTarget,
+ bool aNoContentDispatch);
nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus);
nsresult CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
nsEventStatus* aStatus);
@@ -1046,6 +1053,7 @@ private:
#define NS_EVENT_NEEDS_FRAME(event) \
(!(event)->HasPluginActivationEventMessage() && \
(event)->mMessage != eMouseClick && \
- (event)->mMessage != eMouseDoubleClick)
+ (event)->mMessage != eMouseDoubleClick && \
+ (event)->mMessage != eMouseAuxClick)
#endif // mozilla_EventStateManager_h_
diff --git a/dom/events/WheelHandlingHelper.cpp b/dom/events/WheelHandlingHelper.cpp
index 7665ee922..81f2b6bfa 100644
--- a/dom/events/WheelHandlingHelper.cpp
+++ b/dom/events/WheelHandlingHelper.cpp
@@ -257,6 +257,7 @@ WheelTransaction::OnEvent(WidgetEvent* aEvent)
case eMouseUp:
case eMouseDown:
case eMouseDoubleClick:
+ case eMouseAuxClick:
case eMouseClick:
case eContextMenu:
case eDrop:
diff --git a/dom/events/test/mochitest.ini b/dom/events/test/mochitest.ini
index e100e60a1..0397487bb 100644
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -184,3 +184,4 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_wheel_default_action.html]
[test_bug687787.html]
[test_bug1298970.html]
+[test_bug1304044.html]
diff --git a/dom/events/test/test_bug1304044.html b/dom/events/test/test_bug1304044.html
new file mode 100644
index 000000000..0911dcf73
--- /dev/null
+++ b/dom/events/test/test_bug1304044.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1304044
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1304044</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ var eventsFired = [];
+ var target;
+ var eventsExpected;
+
+ function GetNodeString(node) {
+ if (node == window)
+ return "window";
+ if (node == document)
+ return "document";
+ if (node.id)
+ return node.id;
+ if (node.nodeName)
+ return node.nodeName;
+ return node;
+ }
+
+ function TargetAndListener(listener, target) {
+ this.listener = listener;
+ this.target = target;
+ }
+
+ TargetAndListener.prototype.toString = function() {
+ var targetName = GetNodeString(this.target);
+ var listenerName = GetNodeString(this.listener);
+ return "(listener: " + listenerName + ", target: " + targetName + ")";
+ }
+
+ var tests = [
+ TestAuxClickBubblesForEventListener,
+ TestAuxClickBubblesForOnAuxClick,
+ ];
+
+ function CompareEvents(evt, expected) {
+ return evt && expected && evt.listener == expected.listener &&
+ evt.target == expected.target;
+ }
+
+ function ResetEventsFired() {
+ eventsFired = [];
+ }
+
+ function ClearEventListeners() {
+ for (i in arguments) {
+ arguments[i].removeEventListener("auxclick", log_event);
+ }
+ }
+
+ function ClickTarget(tgt) {
+ synthesizeMouseAtCenter(tgt, {type : "mousedown", button: 2}, window);
+ synthesizeMouseAtCenter(tgt, {type : "mouseup", button: 2}, window);
+ }
+
+ function log_event(e) {
+ eventsFired[eventsFired.length] = new TargetAndListener(this, e.target);
+ }
+
+ function CompareEventsToExpected(expected, actual) {
+ for (var i = 0; i < expected.length || i < actual.length; i++) {
+ ok(CompareEvents(actual[i], expected[i]),
+ "Auxclick receiver's don't match: TargetAndListener " +
+ i + ": Expected: " + expected[i] + ", Actual: " + actual[i]);
+ }
+ }
+
+ function TestAuxClickBubblesForEventListener() {
+ target.addEventListener("auxclick", log_event);
+ document.addEventListener("auxclick", log_event);
+ window.addEventListener("auxclick", log_event);
+
+ ClickTarget(target)
+ CompareEventsToExpected(eventsExpected, eventsFired);
+ ResetEventsFired();
+ ClearEventListeners(target, document, window);
+ }
+
+ function TestAuxClickBubblesForOnAuxClick() {
+ target.onauxclick = log_event;
+ document.onauxclick = log_event;
+ window.onauxclick = log_event;
+
+ ClickTarget(target);
+ CompareEventsToExpected(eventsExpected, eventsFired);
+ ResetEventsFired();
+ }
+
+ function RunTests(){
+ for (var i = 0; i < tests.length; i++) {
+ tests[i]();
+ }
+ }
+
+ function Begin() {
+ target = document.getElementById("target");
+ eventsExpected = [
+ new TargetAndListener(target, target),
+ new TargetAndListener(document, target),
+ new TargetAndListener(window, target),
+ ];
+ RunTests();
+ target.remove();
+ SimpleTest.finish();
+ }
+
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.executeSoon(Begin);
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1304044">Mozilla Bug 1304044</a>
+<p id="display">
+ <div id="target">Target</div>
+</p>
+<div id="content" style:"display:none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_eventTimeStamp.html b/dom/events/test/test_eventTimeStamp.html
index 107a21f87..056203e92 100644
--- a/dom/events/test/test_eventTimeStamp.html
+++ b/dom/events/test/test_eventTimeStamp.html
@@ -17,7 +17,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=77992
<script type="text/js-worker" id="worker-src">
// Simply returns the event timestamp
onmessage = function(evt) {
- postMessage(evt.timeStamp);
+ postMessage(evt.timeStamp + performance.timeOrigin);
}
</script>
<script type="text/js-worker" id="shared-worker-src">
@@ -25,7 +25,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=77992
onconnect = function(evt) {
var port = evt.ports[0];
port.onmessage = function(messageEvt) {
- port.postMessage(messageEvt.timeStamp);
+ port.postMessage(messageEvt.timeStamp + performance.timeOrigin);
};
};
</script>
@@ -57,9 +57,9 @@ function testRegularEvents() {
finishTests();
return;
}
- var timeBeforeEvent = window.performance.now();
- window.addEventListener("load", function(evt) {
- var timeAfterEvent = window.performance.now();
+ var timeBeforeEvent = performance.now();
+ addEventListener("load", function(evt) {
+ var timeAfterEvent = performance.now();
ok(evt.timeStamp >= timeBeforeEvent &&
evt.timeStamp <= timeAfterEvent,
"Event timestamp (" + evt.timeStamp + ") is in expected range: (" +
@@ -71,19 +71,18 @@ function testRegularEvents() {
function testWorkerEvents() {
var blob = new Blob([ document.getElementById("worker-src").textContent ],
{ type: "text/javascript" });
- var worker = new Worker(window.URL.createObjectURL(blob));
+ var worker = new Worker(URL.createObjectURL(blob));
worker.onmessage = function(evt) {
- var timeAfterEvent = window.performance.now();
- // Comparing times across timelines may break now
- // ok(evt.data >= timeBeforeEvent &&
- // evt.data <= timeAfterEvent,
+ var timeAfterEvent = performance.now() + performance.timeOrigin;
+ ok(evt.data >= timeBeforeEvent &&
+ evt.data <= timeAfterEvent,
// "Event timestamp in dedicated worker (" + evt.data +
// ") is in expected range: (" +
// timeBeforeEvent + ", " + timeAfterEvent + ")");
worker.terminate();
testSharedWorkerEvents();
};
- var timeBeforeEvent = window.performance.now();
+ var timeBeforeEvent = performance.now() + performance.timeOrigin;
worker.postMessage("");
}
@@ -93,17 +92,16 @@ function testSharedWorkerEvents() {
{ type: "text/javascript" });
// Delay creation of worker slightly so it is easier to distinguish
// shared worker creation time from this document's navigation start
- window.setTimeout(function() {
- var timeBeforeWorkerCreation = window.performance.now();
- var worker = new SharedWorker(window.URL.createObjectURL(blob));
+ setTimeout(function() {
+ var timeBeforeEvent = performance.now() + performance.timeOrigin;
+ var worker = new SharedWorker(URL.createObjectURL(blob));
worker.port.onmessage = function(evt) {
- var timeAfterEvent = window.performance.now();
- // Comparing times across timelines may break now
- // ok(evt.data >= 0 &&
- // evt.data <= timeAfterEvent - timeBeforeWorkerCreation,
+ var timeAfterEvent = performance.now() + performance.timeOrigin;
+ ok(evt.data >= timeBeforeEvent &&
+ evt.data <= timeAfterEvent,
// "Event timestamp in shared worker (" + evt.data +
// ") is in expected range: (0, " +
- // (timeAfterEvent - timeBeforeWorkerCreation) + ")");
+ // timeBeforeEvent + ", " + timeAfterEvent + ")");
worker.port.close();
finishTests();
};
diff --git a/dom/media/MediaStreamTrack.cpp b/dom/media/MediaStreamTrack.cpp
index 8ccdeb90c..75cdeb1d1 100644
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -165,11 +165,15 @@ MediaStreamTrack::Destroy()
mPrincipalHandleListener->Forget();
mPrincipalHandleListener = nullptr;
}
- for (auto l : mTrackListeners) {
- RemoveListener(l);
+ // Remove all listeners -- avoid iterating over the list we're removing from
+ const nsTArray<RefPtr<MediaStreamTrackListener>> trackListeners(mTrackListeners);
+ for (auto listener : trackListeners) {
+ RemoveListener(listener);
}
- for (auto l : mDirectTrackListeners) {
- RemoveDirectListener(l);
+ // Do the same as above for direct listeners
+ const nsTArray<RefPtr<DirectMediaStreamTrackListener>> directTrackListeners(mDirectTrackListeners);
+ for (auto listener : directTrackListeners) {
+ RemoveDirectListener(listener);
}
}
diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp
index 8dc239b05..93a6b7313 100755
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -13,12 +13,14 @@
#include "PerformanceMeasure.h"
#include "PerformanceObserver.h"
#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 "mozilla/TimerClamping.h"
@@ -38,27 +40,6 @@ using namespace workers;
namespace {
-// Helper classes
-class MOZ_STACK_CLASS PerformanceEntryComparator final
-{
-public:
- bool Equals(const PerformanceEntry* aElem1,
- const PerformanceEntry* aElem2) const
- {
- MOZ_ASSERT(aElem1 && aElem2,
- "Trying to compare null performance entries");
- return aElem1->StartTime() == aElem2->StartTime();
- }
-
- bool LessThan(const PerformanceEntry* aElem1,
- const PerformanceEntry* aElem2) const
- {
- MOZ_ASSERT(aElem1 && aElem2,
- "Trying to compare null performance entries");
- return aElem1->StartTime() < aElem2->StartTime();
- }
-};
-
class PrefEnabledRunnable final
: public WorkerCheckAPIExposureOnMainThreadRunnable
{
@@ -103,14 +84,12 @@ NS_IMPL_RELEASE_INHERITED(Performance, DOMEventTargetHelper)
/* static */ already_AddRefed<Performance>
Performance::CreateForMainThread(nsPIDOMWindowInner* aWindow,
nsDOMNavigationTiming* aDOMTiming,
- nsITimedChannel* aChannel,
- Performance* aParentPerformance)
+ nsITimedChannel* aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<Performance> performance =
- new PerformanceMainThread(aWindow, aDOMTiming, aChannel,
- aParentPerformance);
+ new PerformanceMainThread(aWindow, aDOMTiming, aChannel);
return performance.forget();
}
@@ -142,6 +121,24 @@ Performance::Performance(nsPIDOMWindowInner* aWindow)
Performance::~Performance()
{}
+DOMHighResTimeStamp
+Performance::Now() const
+{
+ TimeDuration duration = TimeStamp::Now() - CreationTimeStamp();
+ return RoundTime(duration.ToMilliseconds());
+}
+
+DOMHighResTimeStamp
+Performance::TimeOrigin()
+{
+ if (!mPerformanceService) {
+ mPerformanceService = PerformanceService::GetOrCreate();
+ }
+
+ MOZ_ASSERT(mPerformanceService);
+ return mPerformanceService->TimeOrigin(CreationTimeStamp());
+}
+
JSObject*
Performance::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
@@ -266,7 +263,7 @@ Performance::ClearMarks(const Optional<nsAString>& aName)
DOMHighResTimeStamp
Performance::ResolveTimestampFromName(const nsAString& aName,
- ErrorResult& aRv)
+ ErrorResult& aRv)
{
AutoTArray<RefPtr<PerformanceEntry>, 1> arr;
DOMHighResTimeStamp ts;
diff --git a/dom/performance/Performance.h b/dom/performance/Performance.h
index bc70589a5..4debecc90 100644
--- a/dom/performance/Performance.h
+++ b/dom/performance/Performance.h
@@ -24,6 +24,7 @@ namespace dom {
class PerformanceEntry;
class PerformanceNavigation;
class PerformanceObserver;
+class PerformanceService;
class PerformanceTiming;
namespace workers {
@@ -45,8 +46,7 @@ public:
static already_AddRefed<Performance>
CreateForMainThread(nsPIDOMWindowInner* aWindow,
nsDOMNavigationTiming* aDOMTiming,
- nsITimedChannel* aChannel,
- Performance* aParentPerformance);
+ nsITimedChannel* aChannel);
static already_AddRefed<Performance>
CreateForWorker(workers::WorkerPrivate* aWorkerPrivate);
@@ -54,21 +54,23 @@ public:
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();
- virtual DOMHighResTimeStamp Now() const = 0;
+ DOMHighResTimeStamp Now() const;
+
+ DOMHighResTimeStamp TimeOrigin();
void Mark(const nsAString& aName, ErrorResult& aRv);
@@ -101,8 +103,6 @@ public:
virtual nsITimedChannel* GetChannel() const = 0;
- virtual Performance* GetParentPerformance() const = 0;
-
protected:
Performance();
explicit Performance(nsPIDOMWindowInner* aWindow);
@@ -126,10 +126,16 @@ protected:
virtual DOMHighResTimeStamp CreationTime() const = 0;
- virtual bool IsPerformanceTimingAttribute(const nsAString& aName) = 0;
+ virtual bool IsPerformanceTimingAttribute(const nsAString& aName)
+ {
+ return false;
+ }
virtual DOMHighResTimeStamp
- GetPerformanceTimingFromString(const nsAString& aTimingName) = 0;
+ GetPerformanceTimingFromString(const nsAString& aTimingName)
+ {
+ return 0;
+ }
bool IsResourceEntryLimitReached() const
{
@@ -147,13 +153,15 @@ protected:
nsTObserverArray<PerformanceObserver*> mObservers;
-private:
+protected:
nsTArray<RefPtr<PerformanceEntry>> mUserEntries;
nsTArray<RefPtr<PerformanceEntry>> mResourceEntries;
uint64_t mResourceTimingBufferSize;
static const uint64_t kDefaultResourceTimingBufferSize = 150;
bool mPendingNotificationObserversTask;
+
+ RefPtr<PerformanceService> mPerformanceService;
};
} // namespace dom
diff --git a/dom/performance/PerformanceEntry.h b/dom/performance/PerformanceEntry.h
index bc4f84f1c..0af9f669e 100644
--- a/dom/performance/PerformanceEntry.h
+++ b/dom/performance/PerformanceEntry.h
@@ -90,6 +90,27 @@ protected:
nsString mEntryType;
};
+// Helper classes
+class MOZ_STACK_CLASS PerformanceEntryComparator final
+{
+public:
+ bool Equals(const PerformanceEntry* aElem1,
+ const PerformanceEntry* aElem2) const
+ {
+ MOZ_ASSERT(aElem1 && aElem2,
+ "Trying to compare null performance entries");
+ return aElem1->StartTime() == aElem2->StartTime();
+ }
+
+ bool LessThan(const PerformanceEntry* aElem1,
+ const PerformanceEntry* aElem2) const
+ {
+ MOZ_ASSERT(aElem1 && aElem2,
+ "Trying to compare null performance entries");
+ return aElem1->StartTime() < aElem2->StartTime();
+ }
+};
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/performance/PerformanceMainThread.cpp b/dom/performance/PerformanceMainThread.cpp
index 86d42c5f8..64c06d3ea 100644
--- a/dom/performance/PerformanceMainThread.cpp
+++ b/dom/performance/PerformanceMainThread.cpp
@@ -6,6 +6,7 @@
#include "PerformanceMainThread.h"
#include "PerformanceNavigation.h"
+#include "nsICacheInfoChannel.h"
namespace mozilla {
namespace dom {
@@ -16,7 +17,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PerformanceMainThread,
Performance)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTiming,
mNavigation,
- mParentPerformance)
+ mDocEntry)
tmp->mMozMemory = nullptr;
mozilla::DropJSObjects(this);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -25,7 +26,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PerformanceMainThread,
Performance)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTiming,
mNavigation,
- mParentPerformance)
+ mDocEntry)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -45,12 +46,10 @@ NS_INTERFACE_MAP_END_INHERITING(Performance)
PerformanceMainThread::PerformanceMainThread(nsPIDOMWindowInner* aWindow,
nsDOMNavigationTiming* aDOMTiming,
- nsITimedChannel* aChannel,
- Performance* aParentPerformance)
+ nsITimedChannel* aChannel)
: Performance(aWindow)
, mDOMTiming(aDOMTiming)
, mChannel(aChannel)
- , mParentPerformance(aParentPerformance)
{
MOZ_ASSERT(aWindow, "Parent window object should be provided");
}
@@ -78,7 +77,7 @@ PerformanceTiming*
PerformanceMainThread::Timing()
{
if (!mTiming) {
- // For navigation timing, the third argument (an nsIHtttpChannel) is null
+ // For navigation timing, the third argument (an nsIHttpChannel) is null
// since the cross-domain redirect were already checked. The last argument
// (zero time) for performance.timing is the navigation start value.
mTiming = new PerformanceTiming(this, mChannel, nullptr,
@@ -108,12 +107,6 @@ PerformanceMainThread::Navigation()
return mNavigation;
}
-DOMHighResTimeStamp
-PerformanceMainThread::Now() const
-{
- return RoundTime(GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now()));
-}
-
/**
* An entry should be added only after the resource is loaded.
* This method is not thread safe and can only be called on the main thread.
@@ -161,27 +154,7 @@ PerformanceMainThread::AddEntry(nsIHttpChannel* channel,
// The PerformanceResourceTiming object will use the PerformanceTiming
// object to get all the required timings.
RefPtr<PerformanceResourceTiming> performanceEntry =
- new PerformanceResourceTiming(performanceTiming, this, entryName);
-
- nsAutoCString protocol;
- channel->GetProtocolVersion(protocol);
- performanceEntry->SetNextHopProtocol(NS_ConvertUTF8toUTF16(protocol));
-
- uint64_t encodedBodySize = 0;
- channel->GetEncodedBodySize(&encodedBodySize);
- performanceEntry->SetEncodedBodySize(encodedBodySize);
-
- uint64_t transferSize = 0;
- channel->GetTransferSize(&transferSize);
- performanceEntry->SetTransferSize(transferSize);
-
- uint64_t decodedBodySize = 0;
- 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()) {
@@ -335,5 +308,65 @@ PerformanceMainThread::CreationTime() const
return GetDOMTiming()->GetNavigationStart();
}
+void
+PerformanceMainThread::EnsureDocEntry()
+{
+ if (!mDocEntry && nsContentUtils::IsPerformanceNavigationTimingEnabled()) {
+ nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
+ RefPtr<PerformanceTiming> timing =
+ new PerformanceTiming(this, mChannel, nullptr, 0);
+ mDocEntry = new PerformanceNavigationTiming(timing, this,
+ httpChannel);
+ }
+}
+
+
+void
+PerformanceMainThread::GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval)
+{
+ aRetval = mResourceEntries;
+ aRetval.AppendElements(mUserEntries);
+
+ EnsureDocEntry();
+ if (mDocEntry) {
+ aRetval.AppendElement(mDocEntry);
+ }
+
+ aRetval.Sort(PerformanceEntryComparator());
+}
+
+void
+PerformanceMainThread::GetEntriesByType(const nsAString& aEntryType,
+ nsTArray<RefPtr<PerformanceEntry>>& aRetval)
+{
+ 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)
+{
+ if (aName.EqualsLiteral("document")) {
+ aRetval.Clear();
+ EnsureDocEntry();
+ if (mDocEntry) {
+ aRetval.AppendElement(mDocEntry);
+ }
+ return;
+ }
+
+ Performance::GetEntriesByName(aName, aEntryType, aRetval);
+}
+
} // dom namespace
} // mozilla namespace
diff --git a/dom/performance/PerformanceMainThread.h b/dom/performance/PerformanceMainThread.h
index 84773f29b..9f0e185fc 100644
--- a/dom/performance/PerformanceMainThread.h
+++ b/dom/performance/PerformanceMainThread.h
@@ -17,16 +17,12 @@ class PerformanceMainThread final : public Performance
public:
PerformanceMainThread(nsPIDOMWindowInner* aWindow,
nsDOMNavigationTiming* aDOMTiming,
- nsITimedChannel* aChannel,
- Performance* aParentPerformance);
+ nsITimedChannel* aChannel);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PerformanceMainThread,
Performance)
- // Performance WebIDL methods
- DOMHighResTimeStamp Now() const override;
-
virtual PerformanceTiming* Timing() override;
virtual PerformanceNavigation* Navigation() override;
@@ -51,10 +47,14 @@ public:
return mChannel;
}
- virtual Performance* GetParentPerformance() const override
- {
- return mParentPerformance;
- }
+ // 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();
@@ -72,12 +72,13 @@ protected:
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;
- RefPtr<Performance> mParentPerformance;
JS::Heap<JSObject*> mMozMemory;
};
diff --git a/dom/performance/PerformanceNavigationTiming.cpp b/dom/performance/PerformanceNavigationTiming.cpp
new file mode 100644
index 000000000..4e00b2bb2
--- /dev/null
+++ b/dom/performance/PerformanceNavigationTiming.cpp
@@ -0,0 +1,96 @@
+/* -*- 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() const
+{
+ return mTiming->GetDOMTiming()->GetUnloadEventStartHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::UnloadEventEnd() const
+{
+ return mTiming->GetDOMTiming()->GetUnloadEventEndHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomInteractive() const
+{
+ return mTiming->GetDOMTiming()->GetDomInteractiveHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomContentLoadedEventStart() const
+{
+ return mTiming->GetDOMTiming()->GetDomContentLoadedEventStartHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomContentLoadedEventEnd() const
+{
+ return mTiming->GetDOMTiming()->GetDomContentLoadedEventEndHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomComplete() const
+{
+ return mTiming->GetDOMTiming()->GetDomCompleteHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::LoadEventStart() const
+{
+ return mTiming->GetDOMTiming()->GetLoadEventStartHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::LoadEventEnd() const
+{
+ return mTiming->GetDOMTiming()->GetLoadEventEndHighRes();
+}
+
+NavigationType
+PerformanceNavigationTiming::Type() const
+{
+ 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:
+ // The type is TYPE_RESERVED or some other value that was later added.
+ // We fallback to the default of Navigate.
+ return NavigationType::Navigate;
+ }
+}
+
+uint16_t
+PerformanceNavigationTiming::RedirectCount() const
+{
+ return mTiming->GetRedirectCount();
+}
diff --git a/dom/performance/PerformanceNavigationTiming.h b/dom/performance/PerformanceNavigationTiming.h
new file mode 100644
index 000000000..8555f1987
--- /dev/null
+++ b/dom/performance/PerformanceNavigationTiming.h
@@ -0,0 +1,71 @@
+/* -*- 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
+
+ // Note that aPerformanceTiming must be initalized with zeroTime = 0
+ // so that timestamps are relative to startTime, as opposed to the
+ // performance.timing object for which timestamps are absolute and has a
+ // zeroTime initialized to navigationStart
+ 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() const;
+ DOMHighResTimeStamp UnloadEventEnd() const;
+
+ DOMHighResTimeStamp DomInteractive() const;
+ DOMHighResTimeStamp DomContentLoadedEventStart() const;
+ DOMHighResTimeStamp DomContentLoadedEventEnd() const;
+ DOMHighResTimeStamp DomComplete() const;
+ DOMHighResTimeStamp LoadEventStart() const;
+ DOMHighResTimeStamp LoadEventEnd() const;
+ NavigationType Type() const;
+ uint16_t RedirectCount() const;
+
+private:
+ ~PerformanceNavigationTiming() {}
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PerformanceNavigationTiming_h___
diff --git a/dom/performance/PerformanceObserver.cpp b/dom/performance/PerformanceObserver.cpp
index 11dd30ac2..d02acfb09 100644
--- a/dom/performance/PerformanceObserver.cpp
+++ b/dom/performance/PerformanceObserver.cpp
@@ -114,12 +114,13 @@ PerformanceObserver::Notify()
RefPtr<PerformanceObserverEntryList> list =
new PerformanceObserverEntryList(this, mQueuedEntries);
+ mQueuedEntries.Clear();
+
ErrorResult rv;
mCallback->Call(this, *list, *this, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
- mQueuedEntries.Clear();
}
void
@@ -170,6 +171,17 @@ PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
mEntryTypes.SwapElements(validEntryTypes);
mPerformance->AddObserver(this);
+
+ if (aOptions.mBuffered) {
+ for (auto entryType : mEntryTypes) {
+ nsTArray<RefPtr<PerformanceEntry>> existingEntries;
+ mPerformance->GetEntriesByType(entryType, existingEntries);
+ if (!existingEntries.IsEmpty()) {
+ mQueuedEntries.AppendElements(existingEntries);
+ }
+ }
+ }
+
mConnected = true;
}
diff --git a/dom/performance/PerformanceObserverEntryList.cpp b/dom/performance/PerformanceObserverEntryList.cpp
index 349103f08..20e818f3d 100644
--- a/dom/performance/PerformanceObserverEntryList.cpp
+++ b/dom/performance/PerformanceObserverEntryList.cpp
@@ -66,6 +66,7 @@ PerformanceObserverEntryList::GetEntries(
aRetval.AppendElement(entry);
}
+ aRetval.Sort(PerformanceEntryComparator());
}
void
@@ -79,6 +80,7 @@ PerformanceObserverEntryList::GetEntriesByType(
aRetval.AppendElement(entry);
}
}
+ aRetval.Sort(PerformanceEntryComparator());
}
void
@@ -88,9 +90,18 @@ PerformanceObserverEntryList::GetEntriesByName(
nsTArray<RefPtr<PerformanceEntry>>& aRetval)
{
aRetval.Clear();
+ const bool typePassed = aEntryType.WasPassed();
for (const RefPtr<PerformanceEntry>& entry : mEntries) {
- if (entry->GetName().Equals(aName)) {
- aRetval.AppendElement(entry);
+ if (!entry->GetName().Equals(aName)) {
+ continue;
}
+
+ if (typePassed &&
+ !entry->GetEntryType().Equals(aEntryType.Value())) {
+ continue;
+ }
+
+ aRetval.AppendElement(entry);
}
+ aRetval.Sort(PerformanceEntryComparator());
}
diff --git a/dom/performance/PerformanceResourceTiming.cpp b/dom/performance/PerformanceResourceTiming.cpp
index 60a20ca28..2eaa4eb9a 100644
--- a/dom/performance/PerformanceResourceTiming.cpp
+++ b/dom/performance/PerformanceResourceTiming.cpp
@@ -25,7 +25,8 @@ NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry)
PerformanceResourceTiming::PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming,
Performance* aPerformance,
- const nsAString& aName)
+ const nsAString& aName,
+ nsIHttpChannel* aChannel)
: PerformanceEntry(aPerformance, aName, NS_LITERAL_STRING("resource")),
mTiming(aPerformanceTiming),
mEncodedBodySize(0),
@@ -33,6 +34,34 @@ PerformanceResourceTiming::PerformanceResourceTiming(PerformanceTiming* aPerform
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()
@@ -42,8 +71,22 @@ PerformanceResourceTiming::~PerformanceResourceTiming()
DOMHighResTimeStamp
PerformanceResourceTiming::StartTime() const
{
- DOMHighResTimeStamp startTime = mTiming->RedirectStartHighRes();
- return startTime ? startTime : mTiming->FetchStartHighRes();
+ // Force the start time to be the earliest of:
+ // - RedirectStart
+ // - WorkerStart
+ // - AsyncOpen
+ // Ignore zero values. The RedirectStart and WorkerStart values
+ // can come from earlier redirected channels prior to the AsyncOpen
+ // time being recorded.
+ DOMHighResTimeStamp redirect = mTiming->RedirectStartHighRes();
+ redirect = redirect ? redirect : DBL_MAX;
+
+ DOMHighResTimeStamp worker = mTiming->WorkerStartHighRes();
+ worker = worker ? worker : DBL_MAX;
+
+ DOMHighResTimeStamp asyncOpen = mTiming->AsyncOpenHighRes();
+
+ return std::min(asyncOpen, std::min(redirect, worker));
}
JSObject*
diff --git a/dom/performance/PerformanceResourceTiming.h b/dom/performance/PerformanceResourceTiming.h
index 2dd6b4a06..98a03327e 100644
--- a/dom/performance/PerformanceResourceTiming.h
+++ b/dom/performance/PerformanceResourceTiming.h
@@ -18,7 +18,7 @@ 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;
@@ -30,7 +30,8 @@ public:
PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming,
Performance* aPerformance,
- const nsAString& aName);
+ const nsAString& aName,
+ nsIHttpChannel* aChannel = nullptr);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -62,6 +63,12 @@ public:
mNextHopProtocol = aNextHopProtocol;
}
+ DOMHighResTimeStamp WorkerStart() const {
+ return mTiming && mTiming->TimingAllowed()
+ ? mTiming->WorkerStartHighRes()
+ : 0;
+ }
+
DOMHighResTimeStamp FetchStart() const {
return mTiming
? mTiming->FetchStartHighRes()
@@ -170,6 +177,7 @@ public:
protected:
virtual ~PerformanceResourceTiming();
+ void SetPropertiesFromChannel(nsIHttpChannel* aChannel);
nsString mInitiatorType;
nsString mNextHopProtocol;
diff --git a/dom/performance/PerformanceService.cpp b/dom/performance/PerformanceService.cpp
new file mode 100644
index 000000000..cf119af89
--- /dev/null
+++ b/dom/performance/PerformanceService.cpp
@@ -0,0 +1,46 @@
+/* -*- 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 "PerformanceService.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h"
+
+namespace mozilla {
+namespace dom {
+
+static StaticRefPtr<PerformanceService> gPerformanceService;
+static StaticMutex gPerformanceServiceMutex;
+
+/* static */ PerformanceService*
+PerformanceService::GetOrCreate()
+{
+ StaticMutexAutoLock al(gPerformanceServiceMutex);
+
+ if (!gPerformanceService) {
+ gPerformanceService = new PerformanceService();
+ ClearOnShutdown(&gPerformanceService);
+ }
+
+ return gPerformanceService;
+}
+
+DOMHighResTimeStamp
+PerformanceService::TimeOrigin(const TimeStamp& aCreationTimeStamp) const
+{
+ return (aCreationTimeStamp - mCreationTimeStamp).ToMilliseconds() +
+ (mCreationEpochTime / PR_USEC_PER_MSEC);
+}
+
+PerformanceService::PerformanceService()
+{
+ mCreationTimeStamp = TimeStamp::Now();
+ mCreationEpochTime = PR_Now();
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/performance/PerformanceService.h b/dom/performance/PerformanceService.h
new file mode 100644
index 000000000..9abbd674d
--- /dev/null
+++ b/dom/performance/PerformanceService.h
@@ -0,0 +1,48 @@
+/* -*- 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 dom_performance_PerformanceService_h
+#define dom_performance_PerformanceService_h
+
+#include "mozilla/TimeStamp.h"
+#include "nsCOMPtr.h"
+#include "nsDOMNavigationTiming.h"
+
+namespace mozilla {
+namespace dom {
+
+// This class is thread-safe.
+
+// We use this singleton for having the correct value of performance.timeOrigin.
+// This value must be calculated on top of the pair:
+// - mCreationTimeStamp (monotonic clock)
+// - mCreationEpochTime (unix epoch time)
+// These 2 values must be taken "at the same time" in order to be used
+// correctly.
+
+class PerformanceService
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PerformanceService)
+
+ static PerformanceService*
+ GetOrCreate();
+
+ DOMHighResTimeStamp
+ TimeOrigin(const TimeStamp& aCreationTimeStamp) const;
+
+private:
+ PerformanceService();
+ ~PerformanceService() = default;
+
+ TimeStamp mCreationTimeStamp;
+ PRTime mCreationEpochTime;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // dom_performance_PerformanceService_h
diff --git a/dom/performance/PerformanceTiming.cpp b/dom/performance/PerformanceTiming.cpp
index e2f76a21f..887a23938 100755
--- a/dom/performance/PerformanceTiming.cpp
+++ b/dom/performance/PerformanceTiming.cpp
@@ -73,6 +73,7 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
{
if (aChannel) {
aChannel->GetAsyncOpen(&mAsyncOpen);
+ aChannel->GetDispatchFetchEventStart(&mWorkerStart);
aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin);
aChannel->GetRedirectCount(&mRedirectCount);
aChannel->GetRedirectStart(&mRedirectStart);
@@ -88,31 +89,39 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
aChannel->GetResponseEnd(&mResponseEnd);
aChannel->GetCacheReadEnd(&mCacheReadEnd);
- // the performance timing api essentially requires that the event timestamps
- // are >= asyncOpen().. but in truth the browser engages in a number of
- // speculative activities that sometimes mean connections and lookups begin
- // earlier. Workaround that here by just using asyncOpen as the minimum
- // timestamp for dns and connection info.
+ // The performance timing api essentially requires that the event timestamps
+ // have a strict relation with each other. The truth, however, is the browser
+ // engages in a number of speculative activities that sometimes mean connections
+ // and lookups begin at different times. Workaround that here by clamping
+ // these values to what we expect FetchStart to be. This means the later of
+ // AsyncOpen or WorkerStart times.
if (!mAsyncOpen.IsNull()) {
- if (!mDomainLookupStart.IsNull() && mDomainLookupStart < mAsyncOpen) {
- mDomainLookupStart = mAsyncOpen;
+ // We want to clamp to the expected FetchStart value. This is later of
+ // the AsyncOpen and WorkerStart values.
+ const TimeStamp* clampTime = &mAsyncOpen;
+ if (!mWorkerStart.IsNull() && mWorkerStart > mAsyncOpen) {
+ clampTime = &mWorkerStart;
}
- if (!mDomainLookupEnd.IsNull() && mDomainLookupEnd < mAsyncOpen) {
- mDomainLookupEnd = mAsyncOpen;
+ if (!mDomainLookupStart.IsNull() && mDomainLookupStart < *clampTime) {
+ mDomainLookupStart = *clampTime;
}
- if (!mConnectStart.IsNull() && mConnectStart < mAsyncOpen) {
- mConnectStart = mAsyncOpen;
+ if (!mDomainLookupEnd.IsNull() && mDomainLookupEnd < *clampTime) {
+ mDomainLookupEnd = *clampTime;
+ }
+
+ if (!mConnectStart.IsNull() && mConnectStart < *clampTime) {
+ mConnectStart = *clampTime;
}
if (mSecureConnection && !mSecureConnectionStart.IsNull() &&
- mSecureConnectionStart < mAsyncOpen) {
- mSecureConnectionStart = mAsyncOpen;
+ mSecureConnectionStart < *clampTime) {
+ mSecureConnectionStart = *clampTime;
}
- if (!mConnectEnd.IsNull() && mConnectEnd < mAsyncOpen) {
- mConnectEnd = mAsyncOpen;
+ if (!mConnectEnd.IsNull() && mConnectEnd < *clampTime) {
+ mConnectEnd = *clampTime;
}
}
}
@@ -131,9 +140,13 @@ PerformanceTiming::FetchStartHighRes()
}
MOZ_ASSERT(!mAsyncOpen.IsNull(), "The fetch start time stamp should always be "
"valid if the performance timing is enabled");
- mFetchStart = (!mAsyncOpen.IsNull())
- ? TimeStampToDOMHighRes(mAsyncOpen)
- : 0.0;
+ if (!mAsyncOpen.IsNull()) {
+ if (!mWorkerStart.IsNull() && mWorkerStart > mAsyncOpen) {
+ mFetchStart = TimeStampToDOMHighRes(mWorkerStart);
+ } else {
+ mFetchStart = TimeStampToDOMHighRes(mAsyncOpen);
+ }
+ }
}
return TimerClamping::ReduceMsTimeValue(mFetchStart);
}
@@ -180,7 +193,7 @@ PerformanceTiming::TimingAllowed() const
return mTimingAllowed;
}
-uint16_t
+uint8_t
PerformanceTiming::GetRedirectCount() const
{
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
@@ -205,6 +218,26 @@ PerformanceTiming::ShouldReportCrossOriginRedirect() const
return (mRedirectCount != 0) && mReportCrossOriginRedirect;
}
+DOMHighResTimeStamp
+PerformanceTiming::AsyncOpenHighRes()
+{
+ if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
+ mAsyncOpen.IsNull()) {
+ return mZeroTime;
+ }
+ return TimeStampToReducedDOMHighResOrFetchStart(mAsyncOpen);
+}
+
+DOMHighResTimeStamp
+PerformanceTiming::WorkerStartHighRes()
+{
+ if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
+ mWorkerStart.IsNull()) {
+ return mZeroTime;
+ }
+ return TimeStampToReducedDOMHighResOrFetchStart(mWorkerStart);
+}
+
/**
* RedirectStartHighRes() is used by both the navigation timing and the
* resource timing. Since, navigation timing and resource timing check and
diff --git a/dom/performance/PerformanceTiming.h b/dom/performance/PerformanceTiming.h
index fc7e7d5bd..435e1bca1 100755
--- a/dom/performance/PerformanceTiming.h
+++ b/dom/performance/PerformanceTiming.h
@@ -139,7 +139,7 @@ public:
return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetUnloadEventEnd());
}
- uint16_t GetRedirectCount() const;
+ uint8_t GetRedirectCount() const;
// Checks if the resource is either same origin as the page that started
// the load, or if the response contains the Timing-Allow-Origin header
@@ -155,7 +155,12 @@ public:
// the timing-allow-origin check in HttpBaseChannel::TimingAllowCheck
bool ShouldReportCrossOriginRedirect() const;
+ // The last channel's AsyncOpen time. This may occur before the FetchStart
+ // in some cases.
+ DOMHighResTimeStamp AsyncOpenHighRes();
+
// High resolution (used by resource timing)
+ DOMHighResTimeStamp WorkerStartHighRes();
DOMHighResTimeStamp FetchStartHighRes();
DOMHighResTimeStamp RedirectStartHighRes();
DOMHighResTimeStamp RedirectEndHighRes();
@@ -237,6 +242,14 @@ public:
return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetLoadEventEnd());
}
+ DOMTimeMilliSec TimeToNonBlankPaint() const
+ {
+ if (!nsContentUtils::IsPerformanceTimingEnabled()) {
+ return 0;
+ }
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetTimeToNonBlankPaint());
+ }
+
private:
~PerformanceTiming();
@@ -253,6 +266,7 @@ private:
DOMHighResTimeStamp mZeroTime;
TimeStamp mAsyncOpen;
+ TimeStamp mWorkerStart;
TimeStamp mRedirectStart;
TimeStamp mRedirectEnd;
TimeStamp mDomainLookupStart;
@@ -265,7 +279,7 @@ private:
TimeStamp mCacheReadStart;
TimeStamp mResponseEnd;
TimeStamp mCacheReadEnd;
- uint16_t mRedirectCount;
+ uint8_t mRedirectCount;
bool mTimingAllowed;
bool mAllRedirectsSameOrigin;
bool mInitialized;
diff --git a/dom/performance/PerformanceWorker.cpp b/dom/performance/PerformanceWorker.cpp
index 85ca2ccd8..f10c58446 100644
--- a/dom/performance/PerformanceWorker.cpp
+++ b/dom/performance/PerformanceWorker.cpp
@@ -23,37 +23,6 @@ PerformanceWorker::~PerformanceWorker()
mWorkerPrivate->AssertIsOnWorkerThread();
}
-DOMHighResTimeStamp
-PerformanceWorker::Now() const
-{
- TimeDuration duration =
- TimeStamp::Now() - mWorkerPrivate->NowBaseTimeStamp();
- return RoundTime(duration.ToMilliseconds());
-}
-
-// To be removed once bug 1124165 lands
-bool
-PerformanceWorker::IsPerformanceTimingAttribute(const nsAString& aName)
-{
- // In workers we just support navigationStart.
- return aName.EqualsASCII("navigationStart");
-}
-
-DOMHighResTimeStamp
-PerformanceWorker::GetPerformanceTimingFromString(const nsAString& aProperty)
-{
- if (!IsPerformanceTimingAttribute(aProperty)) {
- return 0;
- }
-
- if (aProperty.EqualsLiteral("navigationStart")) {
- return mWorkerPrivate->NowBaseTime();
- }
-
- MOZ_CRASH("IsPerformanceTimingAttribute and GetPerformanceTimingFromString are out of sync");
- return 0;
-}
-
void
PerformanceWorker::InsertUserEntry(PerformanceEntry* aEntry)
{
@@ -72,13 +41,13 @@ PerformanceWorker::InsertUserEntry(PerformanceEntry* aEntry)
TimeStamp
PerformanceWorker::CreationTimeStamp() const
{
- return mWorkerPrivate->NowBaseTimeStamp();
+ return mWorkerPrivate->CreationTimeStamp();
}
DOMHighResTimeStamp
PerformanceWorker::CreationTime() const
{
- return mWorkerPrivate->NowBaseTime();
+ return mWorkerPrivate->CreationTime();
}
} // dom namespace
diff --git a/dom/performance/PerformanceWorker.h b/dom/performance/PerformanceWorker.h
index 7eef0d974..346bdd026 100644
--- a/dom/performance/PerformanceWorker.h
+++ b/dom/performance/PerformanceWorker.h
@@ -21,9 +21,6 @@ class PerformanceWorker final : public Performance
public:
explicit PerformanceWorker(workers::WorkerPrivate* aWorkerPrivate);
- // Performance WebIDL methods
- DOMHighResTimeStamp Now() const override;
-
virtual PerformanceTiming* Timing() override
{
MOZ_CRASH("This should not be called on workers.");
@@ -64,12 +61,6 @@ public:
return nullptr;
}
- virtual Performance* GetParentPerformance() const override
- {
- MOZ_CRASH("This should not be called on workers.");
- return nullptr;
- }
-
protected:
~PerformanceWorker();
@@ -80,11 +71,6 @@ protected:
void InsertUserEntry(PerformanceEntry* aEntry) override;
- bool IsPerformanceTimingAttribute(const nsAString& aName) override;
-
- DOMHighResTimeStamp
- GetPerformanceTimingFromString(const nsAString& aTimingName) override;
-
void DispatchBufferFullEvent() override
{
MOZ_CRASH("This should not be called on workers.");
diff --git a/dom/performance/moz.build b/dom/performance/moz.build
index 3286a0a4c..e1f96fec8 100644
--- a/dom/performance/moz.build
+++ b/dom/performance/moz.build
@@ -10,9 +10,11 @@ EXPORTS.mozilla.dom += [
'PerformanceMark.h',
'PerformanceMeasure.h',
'PerformanceNavigation.h',
+ 'PerformanceNavigationTiming.h',
'PerformanceObserver.h',
'PerformanceObserverEntryList.h',
'PerformanceResourceTiming.h',
+ 'PerformanceService.h',
'PerformanceTiming.h',
]
@@ -23,9 +25,11 @@ UNIFIED_SOURCES += [
'PerformanceMark.cpp',
'PerformanceMeasure.cpp',
'PerformanceNavigation.cpp',
+ 'PerformanceNavigationTiming.cpp',
'PerformanceObserver.cpp',
'PerformanceObserverEntryList.cpp',
'PerformanceResourceTiming.cpp',
+ 'PerformanceService.cpp',
'PerformanceTiming.cpp',
'PerformanceWorker.cpp',
]
diff --git a/dom/performance/tests/mochitest.ini b/dom/performance/tests/mochitest.ini
index 18f7f0e45..bee0b2e70 100644
--- a/dom/performance/tests/mochitest.ini
+++ b/dom/performance/tests/mochitest.ini
@@ -1,13 +1,11 @@
[DEFAULT]
support-files =
- performance_observer.html
test_performance_observer.js
test_performance_user_timing.js
test_worker_performance_now.js
worker_performance_user_timing.js
worker_performance_observer.js
sharedworker_performance_user_timing.js
- worker_performance_observer.html
[test_performance_observer.html]
[test_performance_user_timing.html]
@@ -15,3 +13,4 @@ support-files =
[test_worker_observer.html]
[test_sharedWorker_performance_user_timing.html]
[test_worker_performance_now.html]
+[test_timeOrigin.html]
diff --git a/dom/performance/tests/performance_observer.html b/dom/performance/tests/performance_observer.html
deleted file mode 100644
index b8ced9296..000000000
--- a/dom/performance/tests/performance_observer.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
--->
-<!DOCTYPE html>
-<meta charset=utf-8>
-<html>
-<head>
-<title>Test for performance observer</title>
-<script>
-'use strict';
-[
- "promise_test", "test", "setup",
- "assert_true", "assert_equals", "assert_array_equals",
- "assert_throws", "assert_unreached"
-].forEach(func => {
- window[func] = opener[func].bind(opener);
-});
-function done() {
- opener.add_completion_callback(() => {
- self.close();
- });
- opener.done();
-}
-
-</script>
-<script src="test_performance_observer.js"></script>
-</head>
-<body>
-<div id="log"></div>
-<script>
-function makeXHR(aUrl) {
- var xmlhttp = new XMLHttpRequest();
- xmlhttp.open("get", aUrl, true);
- xmlhttp.send();
-}
-
-promise_test(t => {
- var promise = new Promise(resolve => {
- performance.clearResourceTimings();
-
- var observer = new PerformanceObserver(list => resolve(list));
- observer.observe({entryTypes: ['resource']});
- t.add_cleanup(() => observer.disconnect());
- });
-
- makeXHR("test-data.json");
-
- return promise.then(list => {
- assert_equals(list.getEntries().length, 1);
- assert_array_equals(list.getEntries(),
- performance.getEntriesByType("resource"),
- "Observed 'resource' entries should equal to entries obtained by getEntriesByType.");
-
- // getEntries filtering tests
- assert_array_equals(list.getEntries({name: "http://mochi.test:8888/tests/dom/base/test/test-data.json"}),
- performance.getEntriesByName("http://mochi.test:8888/tests/dom/base/test/test-data.json"),
- "getEntries with name filter should return correct results.");
- assert_array_equals(list.getEntries({entryType: "resource"}),
- performance.getEntriesByType("resource"),
- "getEntries with entryType filter should return correct results.");
- assert_array_equals(list.getEntries({initiatorType: "xmlhttprequest"}),
- performance.getEntriesByType("resource"),
- "getEntries with initiatorType filter should return correct results.");
- assert_array_equals(list.getEntries({initiatorType: "link"}),
- [],
- "getEntries with non-existent initiatorType filter should return an empty array.");
- });
-}, "resource-timing test");
-
-done();
-
-</script>
-</body>
diff --git a/dom/performance/tests/test_performance_observer.html b/dom/performance/tests/test_performance_observer.html
index d36878315..7df881bd4 100644
--- a/dom/performance/tests/test_performance_observer.html
+++ b/dom/performance/tests/test_performance_observer.html
@@ -3,15 +3,55 @@
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
+<html>
+<head>
<meta charset=utf-8>
<title>Test for performance observer</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<div id=log></div>
+</head>
+<body>
+<div id="log"></div>
+<script src="test_performance_observer.js"></script>
<script>
-'use strict';
-SpecialPowers.pushPrefEnv({"set": [["dom.enable_performance_observer", true]]},
- function() {
- window.open("performance_observer.html");
- });
+function makeXHR(aUrl) {
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.open("get", aUrl, true);
+ xmlhttp.send();
+}
+
+promise_test(t => {
+ var promise = new Promise(resolve => {
+ performance.clearResourceTimings();
+
+ var observer = new PerformanceObserver(list => resolve(list));
+ observer.observe({entryTypes: ['resource']});
+ t.add_cleanup(() => observer.disconnect());
+ });
+
+ makeXHR("test-data.json");
+
+ return promise.then(list => {
+ assert_equals(list.getEntries().length, 1);
+ assert_array_equals(list.getEntries(),
+ performance.getEntriesByType("resource"),
+ "Observed 'resource' entries should equal to entries obtained by getEntriesByType.");
+
+ // getEntries filtering tests
+ assert_array_equals(list.getEntries({name: "http://mochi.test:8888/tests/dom/base/test/test-data.json"}),
+ performance.getEntriesByName("http://mochi.test:8888/tests/dom/base/test/test-data.json"),
+ "getEntries with name filter should return correct results.");
+ assert_array_equals(list.getEntries({entryType: "resource"}),
+ performance.getEntriesByType("resource"),
+ "getEntries with entryType filter should return correct results.");
+ assert_array_equals(list.getEntries({initiatorType: "xmlhttprequest"}),
+ performance.getEntriesByType("resource"),
+ "getEntries with initiatorType filter should return correct results.");
+ assert_array_equals(list.getEntries({initiatorType: "link"}),
+ [],
+ "getEntries with non-existent initiatorType filter should return an empty array.");
+ });
+}, "resource-timing test");
+
</script>
+</body>
diff --git a/dom/performance/tests/test_performance_user_timing.js b/dom/performance/tests/test_performance_user_timing.js
index cd8261bbd..a15dbebb6 100644
--- a/dom/performance/tests/test_performance_user_timing.js
+++ b/dom/performance/tests/test_performance_user_timing.js
@@ -126,15 +126,18 @@ var steps = [
},
// Test measure
function () {
- ok(true, "Running measure addition with no start/end time test");
- performance.measure("test");
- var measures = performance.getEntriesByType("measure");
- is(measures.length, 1, "number of measures should be 1");
- var measure = measures[0];
- is(measure.name, "test", "measure name should be 'test'");
- is(measure.entryType, "measure", "measure type should be 'measure'");
- is(measure.startTime, 0, "measure start time should be zero");
- ok(measure.duration >= 0, "measure duration should not be negative");
+ // We don't have navigationStart in workers.
+ if ("window" in self) {
+ ok(true, "Running measure addition with no start/end time test");
+ performance.measure("test", "navigationStart");
+ var measures = performance.getEntriesByType("measure");
+ is(measures.length, 1, "number of measures should be 1");
+ var measure = measures[0];
+ is(measure.name, "test", "measure name should be 'test'");
+ is(measure.entryType, "measure", "measure type should be 'measure'");
+ is(measure.startTime, 0, "measure start time should be zero");
+ ok(measure.duration >= 0, "measure duration should not be negative");
+ }
},
function () {
ok(true, "Running measure addition with only start time test");
diff --git a/dom/performance/tests/test_timeOrigin.html b/dom/performance/tests/test_timeOrigin.html
new file mode 100644
index 000000000..5a8a461f3
--- /dev/null
+++ b/dom/performance/tests/test_timeOrigin.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Test for performance.timeOrigin</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="test_performance_user_timing.js"></script>
+ </head>
+ <body>
+ <script type="text/js-worker" id="worker-src">
+ postMessage({ now: performance.now(), timeOrigin: performance.timeOrigin });
+ </script>
+
+ <script type="text/js-worker" id="shared-worker-src">
+ onconnect = function(evt) {
+ evt.ports[0].postMessage({ now: performance.now(), timeOrigin: performance.timeOrigin });
+ };
+ </script>
+
+ <script class="testbody" type="text/javascript">
+
+function testBasic() {
+ ok("timeOrigin" in performance, "Performance.timeOrigin exists.");
+ ok(performance.timeOrigin > 0, "TimeOrigin must be greater than 0.");
+ next();
+}
+
+function testWorker() {
+ var now = performance.now();
+
+ var blob = new Blob([ document.getElementById("worker-src").textContent ],
+ { type: "text/javascript" });
+ var w = new Worker(URL.createObjectURL(blob));
+ w.onmessage = function(e) {
+ ok (e.now + e.timeOrigin > now + performance.now, "Comparing worker.now and window.now");
+ next();
+ }
+}
+
+function testSharedWorker() {
+ var now = performance.now();
+
+ var blob = new Blob([ document.getElementById("shared-worker-src").textContent ],
+ { type: "text/javascript" });
+ var w = new SharedWorker(URL.createObjectURL(blob));
+ w.port.onmessage = function(e) {
+ ok (e.now + e.timeOrigin > now + performance.now, "Comparing worker.now and window.now");
+ next();
+ }
+}
+
+var tests = [ testBasic, testWorker, testSharedWorker ];
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(next);
+ </script>
+ </pre>
+ </body>
+</html>
diff --git a/dom/performance/tests/test_worker_observer.html b/dom/performance/tests/test_worker_observer.html
index b9ed0c964..9a55ef1d5 100644
--- a/dom/performance/tests/test_worker_observer.html
+++ b/dom/performance/tests/test_worker_observer.html
@@ -3,15 +3,16 @@
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
+<html>
+<head>
<meta charset=utf-8>
<title>Test for performance observer in worker</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<div id=log></div>
+</head>
+<body>
+<div id="log"></div>
<script>
-'use strict';
-SpecialPowers.pushPrefEnv({"set": [["dom.enable_performance_observer", true]]},
- function() {
- window.open("worker_performance_observer.html");
- });
+fetch_tests_from_worker(new Worker("worker_performance_observer.js"));
</script>
+</body>
diff --git a/dom/performance/tests/worker_performance_observer.html b/dom/performance/tests/worker_performance_observer.html
deleted file mode 100644
index 613762f52..000000000
--- a/dom/performance/tests/worker_performance_observer.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
--->
-<!DOCTYPE html>
-<meta charset=utf-8>
-<html>
-<head>
-<title>Test for performance observer in worker</title>
-</head>
-<body>
-<div id="log"></div>
-<script>
-[
- "async_test", "test", "setup",
- "assert_true", "assert_equals", "assert_array_equals",
- "assert_throws", "fetch_tests_from_worker"
-].forEach(func => {
- window[func] = opener[func].bind(opener);
-});
-
-function done() {
- opener.add_completion_callback(() => {
- self.close();
- });
- opener.done();
-}
-
-fetch_tests_from_worker(new Worker("worker_performance_observer.js"));
-done();
-</script>
-</body>
diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp
index b7651be1a..291ae576d 100644
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -2532,6 +2532,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
NS_ASSERTION(anEvent.mMessage == eMouseDown ||
anEvent.mMessage == eMouseUp ||
anEvent.mMessage == eMouseDoubleClick ||
+ anEvent.mMessage == eMouseAuxClick ||
anEvent.mMessage == eMouseOver ||
anEvent.mMessage == eMouseOut ||
anEvent.mMessage == eMouseMove ||
@@ -2594,6 +2595,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
switch (anEvent.mMessage) {
case eMouseClick:
case eMouseDoubleClick:
+ case eMouseAuxClick:
// Button up/down events sent instead.
return rv;
default:
@@ -2797,6 +2799,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
switch (anEvent.mMessage) {
case eMouseClick:
case eMouseDoubleClick:
+ case eMouseAuxClick:
// Button up/down events sent instead.
return rv;
default:
diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html
index acbc12e07..4b47d2b4f 100644
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -751,9 +751,11 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceNavigation",
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "PerformanceObserver", nightly: true},
+ "PerformanceNavigationTiming",
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "PerformanceObserverEntryList", nightly: true},
+ "PerformanceObserver"
+// IMPORTANT: Do not change this list without review from a DOM peer!
+ "PerformanceObserverEntryList"
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceResourceTiming",
// IMPORTANT: Do not change this list without review from a DOM peer!
diff --git a/dom/webidl/EventHandler.webidl b/dom/webidl/EventHandler.webidl
index e65a75787..fce6d9b52 100644
--- a/dom/webidl/EventHandler.webidl
+++ b/dom/webidl/EventHandler.webidl
@@ -33,6 +33,7 @@ interface GlobalEventHandlers {
// attribute OnErrorEventHandler onerror;
attribute EventHandler onfocus;
//(Not implemented)attribute EventHandler oncancel;
+ attribute EventHandler onauxclick;
attribute EventHandler oncanplay;
attribute EventHandler oncanplaythrough;
attribute EventHandler onchange;
diff --git a/dom/webidl/Performance.webidl b/dom/webidl/Performance.webidl
index eaede253c..0bd2677df 100644
--- a/dom/webidl/Performance.webidl
+++ b/dom/webidl/Performance.webidl
@@ -17,6 +17,9 @@ typedef sequence <PerformanceEntry> PerformanceEntryList;
interface Performance {
[DependsOn=DeviceState, Affects=Nothing]
DOMHighResTimeStamp now();
+
+ [Constant]
+ readonly attribute DOMHighResTimeStamp timeOrigin;
};
[Exposed=Window]
diff --git a/dom/webidl/PerformanceNavigationTiming.webidl b/dom/webidl/PerformanceNavigationTiming.webidl
new file mode 100644
index 000000000..fa3ecaec4
--- /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;
+};
diff --git a/dom/webidl/PerformanceObserver.webidl b/dom/webidl/PerformanceObserver.webidl
index a3a14cb1e..4cebecbeb 100644
--- a/dom/webidl/PerformanceObserver.webidl
+++ b/dom/webidl/PerformanceObserver.webidl
@@ -9,6 +9,7 @@
dictionary PerformanceObserverInit {
required sequence<DOMString> entryTypes;
+ boolean buffered = false;
};
callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
diff --git a/dom/webidl/PerformanceResourceTiming.webidl b/dom/webidl/PerformanceResourceTiming.webidl
index 021b84ae2..112228325 100644
--- a/dom/webidl/PerformanceResourceTiming.webidl
+++ b/dom/webidl/PerformanceResourceTiming.webidl
@@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
- * http://w3c-test.org/webperf/specs/ResourceTiming/#performanceresourcetiming
+ * https://w3c.github.io/resource-timing/#performanceresourcetiming
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
@@ -12,14 +12,10 @@
interface PerformanceResourceTiming : PerformanceEntry
{
- // A string with the name of that element that initiated the load.
- // If the initiator is a CSS resource, the initiatorType attribute must return
- // the string "css".
- // If the initiator is an XMLHttpRequest object, the initiatorType attribute
- // must return the string "xmlhttprequest".
readonly attribute DOMString initiatorType;
readonly attribute DOMString nextHopProtocol;
+ readonly attribute DOMHighResTimeStamp workerStart;
readonly attribute DOMHighResTimeStamp redirectStart;
readonly attribute DOMHighResTimeStamp redirectEnd;
readonly attribute DOMHighResTimeStamp fetchStart;
diff --git a/dom/webidl/PerformanceTiming.webidl b/dom/webidl/PerformanceTiming.webidl
index e14201440..4aa403a50 100644
--- a/dom/webidl/PerformanceTiming.webidl
+++ b/dom/webidl/PerformanceTiming.webidl
@@ -33,5 +33,11 @@ interface PerformanceTiming {
readonly attribute unsigned long long loadEventStart;
readonly attribute unsigned long long loadEventEnd;
+ // This is a Chrome proprietary extension and not part of the
+ // performance/navigation timing specification.
+ // Returns 0 if a non-blank paint has not happened.
+ [Pref="dom.performance.time_to_non_blank_paint.enabled"]
+ readonly attribute unsigned long long timeToNonBlankPaint;
+
jsonifier;
};
diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
index 8682aee97..8469c9001 100644
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -347,6 +347,7 @@ WEBIDL_FILES = [
'PerformanceMark.webidl',
'PerformanceMeasure.webidl',
'PerformanceNavigation.webidl',
+ 'PerformanceNavigationTiming.webidl',
'PerformanceObserver.webidl',
'PerformanceObserverEntryList.webidl',
'PerformanceResourceTiming.webidl',
diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp
index 780b2f5f8..1f79e2c92 100644
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -12,6 +12,7 @@
#include "nsINetworkInterceptController.h"
#include "nsIOutputStream.h"
#include "nsIScriptError.h"
+#include "nsITimedChannel.h"
#include "nsIUnicodeDecoder.h"
#include "nsIUnicodeEncoder.h"
#include "nsContentPolicyUtils.h"
@@ -108,6 +109,12 @@ NS_IMETHODIMP
CancelChannelRunnable::Run()
{
MOZ_ASSERT(NS_IsMainThread());
+
+ // TODO: When bug 1204254 is implemented, this time marker should be moved to
+ // the point where the body of the network request is complete.
+ mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
+ mChannel->SaveTimeStampsToUnderlyingChannel();
+
mChannel->Cancel(mStatus);
mRegistration->MaybeScheduleUpdate();
return NS_OK;
@@ -230,6 +237,9 @@ public:
return NS_OK;
}
+ mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
+ mChannel->SaveTimeStampsToUnderlyingChannel();
+
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(underlyingChannel, "service-worker-synthesized-response", nullptr);
diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp
index eaa548f95..24b2e11e6 100644
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -13,6 +13,7 @@
#include "nsINetworkInterceptController.h"
#include "nsIPushErrorReporter.h"
#include "nsISupportsImpl.h"
+#include "nsITimedChannel.h"
#include "nsIUploadChannel2.h"
#include "nsNetUtil.h"
#include "nsProxyRelease.h"
@@ -1255,6 +1256,7 @@ class FetchEventRunnable : public ExtendableFunctionalEventWorkerRunnable
nsCString mMethod;
nsString mClientId;
bool mIsReload;
+ bool mMarkLaunchServiceWorkerEnd;
RequestCache mCacheMode;
RequestMode mRequestMode;
RequestRedirect mRequestRedirect;
@@ -1273,13 +1275,15 @@ public:
const nsACString& aScriptSpec,
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
const nsAString& aDocumentId,
- bool aIsReload)
+ bool aIsReload,
+ bool aMarkLaunchServiceWorkerEnd)
: ExtendableFunctionalEventWorkerRunnable(
aWorkerPrivate, aKeepAliveToken, aRegistration)
, mInterceptedChannel(aChannel)
, mScriptSpec(aScriptSpec)
, mClientId(aDocumentId)
, mIsReload(aIsReload)
+ , mMarkLaunchServiceWorkerEnd(aMarkLaunchServiceWorkerEnd)
, mCacheMode(RequestCache::Default)
, mRequestMode(RequestMode::No_cors)
, mRequestRedirect(RequestRedirect::Follow)
@@ -1417,6 +1421,12 @@ public:
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
+
+ if (mMarkLaunchServiceWorkerEnd) {
+ mInterceptedChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
+ }
+
+ mInterceptedChannel->SetDispatchFetchEventEnd(TimeStamp::Now());
return DispatchFetchEvent(aCx, aWorkerPrivate);
}
@@ -1445,6 +1455,10 @@ private:
NS_IMETHOD Run() override
{
AssertIsOnMainThread();
+
+ mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
+ mChannel->SaveTimeStampsToUnderlyingChannel();
+
nsresult rv = mChannel->ResetInterception();
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to resume intercepted network request");
@@ -1520,6 +1534,8 @@ private:
event->PostInit(mInterceptedChannel, mRegistration, mScriptSpec);
event->SetTrusted(true);
+ mInterceptedChannel->SetHandleFetchEventStart(TimeStamp::Now());
+
RefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
@@ -1614,9 +1630,21 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsCOMPtr<nsIRunnable> failRunnable =
NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception);
- nsresult rv = SpawnWorkerIfNeeded(FetchEvent, failRunnable, aLoadGroup);
+ aChannel->SetLaunchServiceWorkerStart(TimeStamp::Now());
+ aChannel->SetDispatchFetchEventStart(TimeStamp::Now());
+
+ bool newWorkerCreated = false;
+ nsresult rv = SpawnWorkerIfNeeded(FetchEvent,
+ failRunnable,
+ &newWorkerCreated,
+ aLoadGroup);
+
NS_ENSURE_SUCCESS(rv, rv);
+ if (!newWorkerCreated) {
+ aChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
+ }
+
nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
@@ -1646,7 +1674,7 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
RefPtr<FetchEventRunnable> r =
new FetchEventRunnable(mWorkerPrivate, token, handle,
mInfo->ScriptSpec(), regInfo,
- aDocumentId, aIsReload);
+ aDocumentId, aIsReload, newWorkerCreated);
rv = r->Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@@ -1669,6 +1697,7 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsresult
ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
nsIRunnable* aLoadFailedRunnable,
+ bool* aNewWorkerCreated,
nsILoadGroup* aLoadGroup)
{
AssertIsOnMainThread();
@@ -1679,6 +1708,12 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
// the overriden load group when intercepting a fetch.
MOZ_ASSERT_IF(aWhy == FetchEvent, aLoadGroup);
+ // Defaults to no new worker created, but if there is one, we'll set the value
+ // to true at the end of this function.
+ if (aNewWorkerCreated) {
+ *aNewWorkerCreated = false;
+ }
+
if (mWorkerPrivate) {
mWorkerPrivate->UpdateOverridenLoadGroup(aLoadGroup);
RenewKeepAliveToken(aWhy);
@@ -1762,6 +1797,10 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
RenewKeepAliveToken(aWhy);
+ if (aNewWorkerCreated) {
+ *aNewWorkerCreated = true;
+ }
+
return NS_OK;
}
diff --git a/dom/workers/ServiceWorkerPrivate.h b/dom/workers/ServiceWorkerPrivate.h
index 8d59ea1d0..911b07a11 100644
--- a/dom/workers/ServiceWorkerPrivate.h
+++ b/dom/workers/ServiceWorkerPrivate.h
@@ -189,6 +189,7 @@ private:
nsresult
SpawnWorkerIfNeeded(WakeUpReason aWhy,
nsIRunnable* aLoadFailedRunnable,
+ bool* aNewWorkerCreated = nullptr,
nsILoadGroup* aLoadGroup = nullptr);
~ServiceWorkerPrivate();
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index bd8a33032..8848e881a 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2419,8 +2419,6 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
MOZ_ASSERT_IF(mIsChromeWorker, mIsSecureContext);
MOZ_ASSERT(IsDedicatedWorker());
- mNowBaseTimeStamp = aParent->NowBaseTimeStamp();
- mNowBaseTimeHighRes = aParent->NowBaseTime();
if (aParent->mParentFrozen) {
Freeze(nullptr);
@@ -2451,18 +2449,6 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
.creationOptions().setSecureContext(true);
}
- if (IsDedicatedWorker() && mLoadInfo.mWindow &&
- mLoadInfo.mWindow->GetPerformance()) {
- mNowBaseTimeStamp = mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
- GetNavigationStartTimeStamp();
- mNowBaseTimeHighRes =
- mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
- GetNavigationStartHighRes();
- } else {
- mNowBaseTimeStamp = CreationTimeStamp();
- mNowBaseTimeHighRes = CreationTime();
- }
-
// Our parent can get suspended after it initiates the async creation
// of a new worker thread. In this case suspend the new worker as well.
if (mLoadInfo.mWindow && mLoadInfo.mWindow->IsSuspended()) {
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index 465c0f9a3..28283bed7 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -216,8 +216,6 @@ private:
WorkerType mWorkerType;
TimeStamp mCreationTimeStamp;
DOMHighResTimeStamp mCreationTimeHighRes;
- TimeStamp mNowBaseTimeStamp;
- DOMHighResTimeStamp mNowBaseTimeHighRes;
protected:
// The worker is owned by its thread, which is represented here. This is set
@@ -579,14 +577,11 @@ public:
return mCreationTimeHighRes;
}
- TimeStamp NowBaseTimeStamp() const
+ DOMHighResTimeStamp TimeStampToDOMHighRes(const TimeStamp& aTimeStamp) const
{
- return mNowBaseTimeStamp;
- }
-
- DOMHighResTimeStamp NowBaseTime() const
- {
- return mNowBaseTimeHighRes;
+ MOZ_ASSERT(!aTimeStamp.IsNull());
+ TimeDuration duration = aTimeStamp - mCreationTimeStamp;
+ return duration.ToMilliseconds();
}
nsIPrincipal*
diff --git a/dom/workers/test/serviceworkers/chrome.ini b/dom/workers/test/serviceworkers/chrome.ini
index e064e7fd0..6d7dbebd0 100644
--- a/dom/workers/test/serviceworkers/chrome.ini
+++ b/dom/workers/test/serviceworkers/chrome.ini
@@ -3,6 +3,8 @@ skip-if = os == 'android'
support-files =
chrome_helpers.js
empty.js
+ fetch.js
+ hello.html
serviceworker.html
serviceworkerinfo_iframe.html
serviceworkermanager_iframe.html
@@ -10,6 +12,7 @@ support-files =
worker.js
worker2.js
+[test_devtools_serviceworker_interception.html]
[test_privateBrowsing.html]
[test_serviceworkerinfo.xul]
[test_serviceworkermanager.xul]
diff --git a/dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html b/dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html
new file mode 100644
index 000000000..d49ebb2c9
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html
@@ -0,0 +1,168 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1168875 - test devtools serviceworker interception.</title>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet"
+ type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+// Constants
+const Ci = Components.interfaces;
+const workerScope = "http://mochi.test:8888/chrome/dom/workers/test/serviceworkers/";
+const workerURL = workerScope + "fetch.js";
+const contentPage = workerScope + "hello.html";
+
+function createTestWindow(aURL) {
+ var mainwindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ var win = mainwindow.OpenBrowserWindow(contentPage);
+
+ return new Promise(aResolve => {
+ win.addEventListener("DOMContentLoaded", function callback() {
+ if (win.content.location.href != aURL) {
+ win.gBrowser.loadURI(aURL);
+ return;
+ }
+
+ win.removeEventListener("DOMContentLoaded", callback);
+ aResolve(win.content);
+ });
+ });
+}
+
+function executeTest(aWindow) {
+ var registration;
+
+ return Promise.resolve()
+ // Should not be intercepted.
+ .then(_ => fetchAndCheckTimedChannel(aWindow, false, true, "hello.html"))
+
+ // Regist a service worker.
+ .then(_ => register(aWindow, workerURL, workerScope))
+ .then(r => registration = r)
+
+ // Should be intercpeted and synthesized.
+ .then(_ => fetchAndCheckTimedChannel(aWindow, true, false, "fake.html"))
+
+ // Should be intercepted but still fetch from network.
+ .then(_ => fetchAndCheckTimedChannel(aWindow, true, true,
+ "hello.html?ForBypassingHttpCache"))
+
+ // Tear down
+ .then(_ => registration.unregister());
+}
+
+function register(aWindow, aURL, aScope) {
+ return aWindow.navigator.serviceWorker.register(aURL, {scope: aScope})
+ .then(r => {
+ var worker = r.installing;
+ return new Promise(function(aResolve) {
+ worker.onstatechange = function() {
+ if (worker.state == "activated") {
+ aResolve(r);
+ }
+ }
+ });
+ });
+}
+
+function fetchAndCheckTimedChannel(aWindow, aIntercepted, aFetch, aURL) {
+ var resolveFunction;
+ var promise = new Promise(aResolve => resolveFunction = aResolve);
+
+ var topic = aFetch ? "http-on-examine-response"
+ : "service-worker-synthesized-response";
+
+ function observer(aSubject) {
+ var channel = aSubject.QueryInterface(Ci.nsIChannel);
+ ok(channel.URI.spec.endsWith(aURL));
+
+ var tc = aSubject.QueryInterface(Ci.nsITimedChannel);
+
+ // Check service worker related timings.
+ var serviceWorkerTimings = [{start: tc.launchServiceWorkerStartTime,
+ end: tc.launchServiceWorkerEndTime},
+ {start: tc.dispatchFetchEventStartTime,
+ end: tc.dispatchFetchEventEndTime},
+ {start: tc.handleFetchEventStartTime,
+ end: tc.handleFetchEventEndTime}];
+ if (aIntercepted) {
+ serviceWorkerTimings.reduce((aPreviousTimings, aCurrentTimings) => {
+ ok(aPreviousTimings.start <= aCurrentTimings.start,
+ "Start time order check.");
+ ok(aPreviousTimings.end <= aCurrentTimings.end,
+ "End time order check.");
+ ok(aCurrentTimings.start <= aCurrentTimings.end,
+ "Start time should be smaller than end time.");
+ return aCurrentTimings;
+ });
+ } else {
+ serviceWorkerTimings.forEach(aTimings => {
+ is(aTimings.start, 0);
+ is(aTimings.end, 0);
+ });
+ }
+
+ // Check network related timings.
+ var networkTimings = [tc.domainLookupStartTime,
+ tc.domainLookupEndTime,
+ tc.connectStartTime,
+ tc.connectEndTime,
+ tc.requestStartTime,
+ tc.responseStartTime,
+ tc.responseEndTime];
+ if (aFetch) {
+ networkTimings.reduce((aPreviousTiming, aCurrentTiming) => {
+ ok(aPreviousTiming <= aCurrentTiming);
+ return aCurrentTiming;
+ });
+ } else {
+ networkTimings.forEach(aTiming => is(aTiming, 0));
+ }
+
+ SpecialPowers.removeObserver(observer, topic);
+ resolveFunction();
+ }
+
+ SpecialPowers.addObserver(observer, topic, false);
+
+ // return promise;
+ return Promise.all([aWindow.fetch(aURL), promise]);
+}
+
+function runTest() {
+ return Promise.resolve()
+ .then(_ => createTestWindow(contentPage))
+ .then(w => executeTest(w))
+ .catch(e => ok(false, "Some test failed with error " + e))
+ .then(_ => SimpleTest.finish());
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [
+ ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+ ["dom.serviceWorkers.enabled", true],
+ ["dom.serviceWorkers.testing.enabled", true],
+]}, runTest);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
index 9dbfcc099..a4d498fb8 100644
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -172,9 +172,9 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceMeasure",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserver", nightly: true },
+ "PerformanceObserver",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserverEntryList", nightly: true },
+ "PerformanceObserverEntryList",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Request",
// IMPORTANT: Do not change this list without review from a DOM peer!
diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js
index e0647682c..6fe5fcaff 100644
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -163,9 +163,9 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceMeasure",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserver", nightly: true },
+ "PerformanceObserver",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserverEntryList", nightly: true },
+ "PerformanceObserverEntryList",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Request",
// IMPORTANT: Do not change this list without review from a DOM peer!
diff --git a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
index 4913702aa..032161722 100644
--- a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
+++ b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
@@ -322,7 +322,7 @@ public:
void trace(JSTracer* trc) {
for (uint8_t i = 0; i < mCount; ++i) {
if (mArray[i].type == nsXPTType::T_JSVAL) {
- JS::UnsafeTraceRoot(trc, &mArray[i].val.j, "txParam value");
+ JS::UnsafeTraceRoot(trc, &mArray[i].val.j.asValueRef(), "txParam value");
}
}
}