Bug 1169068 - Performance.translateTime(), r=bz

This commit is contained in:
Andrea Marchesini 2015-11-19 14:04:47 +00:00
parent dfd40750f7
commit 74dc0347bd
11 changed files with 189 additions and 34 deletions

View File

@ -11,6 +11,7 @@
#include "nsDOMNavigationTiming.h"
#include "nsContentUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsGlobalWindow.h"
#include "nsIDOMWindow.h"
#include "nsILoadInfo.h"
#include "nsIURI.h"
@ -29,6 +30,8 @@
#include "mozilla/Preferences.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/TimeStamp.h"
#include "SharedWorker.h"
#include "ServiceWorker.h"
#include "js/HeapAPI.h"
#include "GeckoProfiler.h"
#include "WorkerPrivate.h"
@ -500,12 +503,7 @@ nsPerformance::Navigation()
DOMHighResTimeStamp
nsPerformance::Now() const
{
double nowTimeMs = GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now());
// Round down to the nearest 5us, because if the timer is too accurate people
// can do nasty timing attacks with it. See similar code in the worker
// Performance implementation.
const double maxResolutionMs = 0.005;
return floor(nowTimeMs / maxResolutionMs) * maxResolutionMs;
return RoundTime(GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now()));
}
JSObject*
@ -802,15 +800,16 @@ nsPerformance::InsertUserEntry(PerformanceEntry* aEntry)
PerformanceBase::InsertUserEntry(aEntry);
}
DOMHighResTimeStamp
nsPerformance::DeltaFromNavigationStart(DOMHighResTimeStamp aTime)
TimeStamp
nsPerformance::CreationTimeStamp() const
{
// If the time we're trying to convert is equal to zero, it hasn't been set
// yet so just return 0.
if (aTime == 0) {
return 0;
}
return aTime - GetDOMTiming()->GetNavigationStart();
return GetDOMTiming()->GetNavigationStartTimeStamp();
}
DOMHighResTimeStamp
nsPerformance::CreationTime() const
{
return GetDOMTiming()->GetNavigationStart();
}
// PerformanceBase
@ -922,6 +921,48 @@ PerformanceBase::ClearResourceTimings()
mResourceEntries.Clear();
}
DOMHighResTimeStamp
PerformanceBase::TranslateTime(DOMHighResTimeStamp aTime,
const WindowOrWorkerOrSharedWorkerOrServiceWorker& aTimeSource,
ErrorResult& aRv)
{
TimeStamp otherCreationTimeStamp;
if (aTimeSource.IsWindow()) {
RefPtr<nsPerformance> performance = aTimeSource.GetAsWindow().GetPerformance();
if (NS_WARN_IF(!performance)) {
aRv.Throw(NS_ERROR_FAILURE);
}
otherCreationTimeStamp = performance->CreationTimeStamp();
} else if (aTimeSource.IsWorker()) {
otherCreationTimeStamp = aTimeSource.GetAsWorker().NowBaseTimeStamp();
} else if (aTimeSource.IsSharedWorker()) {
SharedWorker& sharedWorker = aTimeSource.GetAsSharedWorker();
WorkerPrivate* workerPrivate = sharedWorker.GetWorkerPrivate();
otherCreationTimeStamp = workerPrivate->NowBaseTimeStamp();
} else if (aTimeSource.IsServiceWorker()) {
ServiceWorker& serviceWorker = aTimeSource.GetAsServiceWorker();
WorkerPrivate* workerPrivate = serviceWorker.GetWorkerPrivate();
otherCreationTimeStamp = workerPrivate->NowBaseTimeStamp();
} else {
MOZ_CRASH("This should not be possible.");
}
return RoundTime(
aTime + (otherCreationTimeStamp - CreationTimeStamp()).ToMilliseconds());
}
DOMHighResTimeStamp
PerformanceBase::RoundTime(double aTime) const
{
// Round down to the nearest 5us, because if the timer is too accurate people
// can do nasty timing attacks with it. See similar code in the worker
// Performance implementation.
const double maxResolutionMs = 0.005;
return floor(aTime / maxResolutionMs) * maxResolutionMs;
}
void
PerformanceBase::Mark(const nsAString& aName, ErrorResult& aRv)
{
@ -976,7 +1017,7 @@ PerformanceBase::ResolveTimestampFromName(const nsAString& aName,
return 0;
}
return DeltaFromNavigationStart(ts);
return ts - CreationTime();
}
void

View File

@ -23,10 +23,15 @@ class nsPerformance;
class nsIHttpChannel;
namespace mozilla {
class ErrorResult;
namespace dom {
class PerformanceEntry;
class PerformanceObserver;
class PerformanceEntry;
class PerformanceObserver;
class WindowOrWorkerOrSharedWorkerOrServiceWorker;
} // namespace dom
} // namespace mozilla
@ -313,6 +318,11 @@ public:
virtual DOMHighResTimeStamp Now() const = 0;
DOMHighResTimeStamp
TranslateTime(DOMHighResTimeStamp aTime,
const mozilla::dom::WindowOrWorkerOrSharedWorkerOrServiceWorker& aTimeSource,
mozilla::ErrorResult& aRv);
void Mark(const nsAString& aName, mozilla::ErrorResult& aRv);
void ClearMarks(const mozilla::dom::Optional<nsAString>& aName);
void Measure(const nsAString& aName,
@ -344,8 +354,9 @@ protected:
virtual void DispatchBufferFullEvent() = 0;
virtual DOMHighResTimeStamp
DeltaFromNavigationStart(DOMHighResTimeStamp aTime) = 0;
virtual mozilla::TimeStamp CreationTimeStamp() const = 0;
virtual DOMHighResTimeStamp CreationTime() const = 0;
virtual bool IsPerformanceTimingAttribute(const nsAString& aName) = 0;
@ -363,6 +374,8 @@ protected:
void RunNotificationObserversTask();
void QueueEntry(PerformanceEntry* aEntry);
DOMHighResTimeStamp RoundTime(double aTime) const;
nsTObserverArray<PerformanceObserver*> mObservers;
private:
@ -433,7 +446,11 @@ public:
IMPL_EVENT_HANDLER(resourcetimingbufferfull)
private:
mozilla::TimeStamp CreationTimeStamp() const override;
DOMHighResTimeStamp CreationTime() const override;
protected:
~nsPerformance();
nsISupports* GetAsISupports() override
@ -445,9 +462,6 @@ private:
bool IsPerformanceTimingAttribute(const nsAString& aName) override;
DOMHighResTimeStamp
DeltaFromNavigationStart(DOMHighResTimeStamp aTime) override;
DOMHighResTimeStamp
GetPerformanceTimingFromString(const nsAString& aTimingName) override;

View File

@ -0,0 +1 @@
/* nothing here */

View File

@ -256,6 +256,7 @@ support-files =
file_explicit_user_agent.sjs
referrer_change_server.sjs
file_change_policy_redirect.html
empty_worker.js
[test_anonymousContent_api.html]
[test_anonymousContent_append_after_reflow.html]
@ -855,3 +856,4 @@ skip-if = e10s || os != 'linux' || buildapp != 'browser'
[test_change_policy.html]
skip-if = buildapp == 'b2g' #no ssl support
[test_document.all_iteration.html]
[test_performance_translate.html]

View File

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for performance.translate()</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>
<pre id="test">
<script class="testbody" type="text/javascript">
function testBasic() {
ok("translateTime" in performance, "Performance.translateTime exists.");
try {
performance.translateTime(0, null);
ok(false, "Wrong use of performance.translateTime.");
} catch(e) {
ok(true, "Wrong use of performance.translateTime.");
}
next();
}
function testWindow() {
is(performance.translateTime(42, this), 42, "translating time with the same window.");
var now = performance.now();
var ifr = document.createElement('iframe');
ifr.src = 'file_empty.html';
document.body.appendChild(ifr);
ifr.onload = function() {
var a = performance.translateTime(0, ifr.contentWindow);
ok (a >= now, "Time has been translated from a window that started loading later than we did");
next();
}
}
function testWorker() {
var now = performance.now();
var w = new Worker('empty_worker.js');
var a = performance.translateTime(0, w);
// bug 1226147
todo (a >= now, "Time has been translated from a Worker that started loading later than we did");
next();
}
function testSharedWorker() {
var now = performance.now();
var w = new SharedWorker('empty_worker.js');
var a = performance.translateTime(0, w);
ok (a >= now, "Time has been translated from a SharedWorker that started loading later than we did");
next();
}
var tests = [ testBasic, testWindow, testWorker, testSharedWorker ];
function next() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(next);
</script>
</pre>
</body>
</html>

View File

@ -4,10 +4,10 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://www.w3.org/TR/hr-time/
* http://w3c.github.io/hr-time/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
* Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang).
* W3C liability, trademark and document use rules apply.
*/
typedef double DOMHighResTimeStamp;
@ -17,6 +17,9 @@ typedef sequence <PerformanceEntry> PerformanceEntryList;
interface Performance {
[DependsOn=DeviceState, Affects=Nothing]
DOMHighResTimeStamp now();
[Throws]
DOMHighResTimeStamp translateTime(DOMHighResTimeStamp time, (Window or Worker or SharedWorker or ServiceWorker) timeSource);
};
[Exposed=Window]

View File

@ -79,14 +79,16 @@ Performance::InsertUserEntry(PerformanceEntry* aEntry)
PerformanceBase::InsertUserEntry(aEntry);
}
DOMHighResTimeStamp
Performance::DeltaFromNavigationStart(DOMHighResTimeStamp aTime)
TimeStamp
Performance::CreationTimeStamp() const
{
if (aTime == 0) {
return 0;
}
return mWorkerPrivate->NowBaseTimeStamp();
}
return aTime - mWorkerPrivate->NowBaseTimeHighRes();
DOMHighResTimeStamp
Performance::CreationTime() const
{
return mWorkerPrivate->NowBaseTimeHighRes();
}
void

View File

@ -55,8 +55,9 @@ private:
DOMHighResTimeStamp
GetPerformanceTimingFromString(const nsAString& aTimingName) override;
DOMHighResTimeStamp
DeltaFromNavigationStart(DOMHighResTimeStamp aTime) override;
TimeStamp CreationTimeStamp() const override;
DOMHighResTimeStamp CreationTime() const override;
};
END_WORKERS_NAMESPACE

View File

@ -101,6 +101,13 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo));
}
WorkerPrivate*
ServiceWorker::GetWorkerPrivate() const
{
ServiceWorkerPrivate* workerPrivate = mInfo->WorkerPrivate();
return workerPrivate->GetWorkerPrivate();
}
} // namespace workers
} // namespace dom
} // namespace mozilla

View File

@ -67,6 +67,9 @@ public:
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv);
WorkerPrivate*
GetWorkerPrivate() const;
private:
// This class can only be created from the ServiceWorkerManager.
ServiceWorker(nsPIDOMWindow* aWindow, ServiceWorkerInfo* aInfo);

View File

@ -128,6 +128,12 @@ public:
void
NoteStoppedControllingDocuments();
WorkerPrivate*
GetWorkerPrivate() const
{
return mWorkerPrivate;
}
private:
enum WakeUpReason {
FetchEvent = 0,