Bug 1165796 - Part 2: Implement PerformanceObserver.r=baku

This commit is contained in:
Hiroyuki Ikezoe 2015-08-17 15:13:20 -07:00
parent 84de9ab09d
commit 6281743182
21 changed files with 883 additions and 0 deletions

View File

@ -15,6 +15,7 @@ class nsISupports;
namespace mozilla {
namespace dom {
class PerformanceResourceTiming;
// http://www.w3.org/TR/performance-timeline/#performanceentry
class PerformanceEntry : public nsISupports,
@ -78,6 +79,11 @@ public:
return 0;
}
virtual const PerformanceResourceTiming* ToResourceTiming() const
{
return nullptr;
}
protected:
nsCOMPtr<nsISupports> mParent;
nsString mName;

View File

@ -0,0 +1,154 @@
/* -*- 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 "PerformanceObserver.h"
#include "mozilla/dom/PerformanceBinding.h"
#include "mozilla/dom/PerformanceEntryBinding.h"
#include "mozilla/dom/PerformanceObserverBinding.h"
#include "mozilla/dom/workers/bindings/Performance.h"
#include "nsPerformance.h"
#include "nsPIDOMWindow.h"
#include "nsQueryObject.h"
#include "nsString.h"
#include "PerformanceEntry.h"
#include "PerformanceObserverEntryList.h"
#include "WorkerPrivate.h"
#include "WorkerScope.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::workers;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceObserver,
mOwner,
mPerformance,
mCallback)
NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceObserver)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceObserver)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceObserver)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
PerformanceObserver::PerformanceObserver(nsPIDOMWindow* aOwner,
PerformanceObserverCallback& aCb)
: mOwner(aOwner)
, mCallback(&aCb)
{
MOZ_ASSERT(mOwner);
mPerformance = aOwner->GetPerformance();
}
PerformanceObserver::PerformanceObserver(WorkerPrivate* aWorkerPrivate,
PerformanceObserverCallback& aCb)
: mCallback(&aCb)
{
MOZ_ASSERT(aWorkerPrivate);
mPerformance = aWorkerPrivate->GlobalScope()->GetPerformance();
}
PerformanceObserver::~PerformanceObserver()
{
}
// static
already_AddRefed<PerformanceObserver>
PerformanceObserver::Constructor(const GlobalObject& aGlobal,
PerformanceObserverCallback& aCb,
ErrorResult& aRv)
{
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindow> ownerWindow =
do_QueryInterface(aGlobal.GetAsSupports());
if (!ownerWindow) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
MOZ_ASSERT(ownerWindow->IsInnerWindow());
nsRefPtr<PerformanceObserver> observer =
new PerformanceObserver(ownerWindow, aCb);
return observer.forget();
}
JSContext* cx = aGlobal.Context();
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
MOZ_ASSERT(workerPrivate);
nsRefPtr<PerformanceObserver> observer =
new PerformanceObserver(workerPrivate, aCb);
return observer.forget();
}
JSObject*
PerformanceObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return PerformanceObserverBinding::Wrap(aCx, this, aGivenProto);
}
void
PerformanceObserver::Notify(PerformanceEntry* aEntry)
{
MOZ_ASSERT(aEntry);
nsAutoString entryType;
aEntry->GetEntryType(entryType);
if (!mEntryTypes.Contains<nsString>(entryType)) {
return;
}
nsRefPtr<PerformanceObserverEntryList> list = new PerformanceObserverEntryList(this);
list->AppendEntry(aEntry);
ErrorResult rv;
mCallback->Call(this, *list, *this, rv);
NS_WARN_IF(rv.Failed());
}
static nsString sValidTypeNames[7] = {
NS_LITERAL_STRING("composite"),
NS_LITERAL_STRING("mark"),
NS_LITERAL_STRING("measure"),
NS_LITERAL_STRING("navigation"),
NS_LITERAL_STRING("render"),
NS_LITERAL_STRING("resource"),
NS_LITERAL_STRING("server")
};
void
PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
ErrorResult& aRv)
{
if (aOptions.mEntryTypes.IsEmpty()) {
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return;
}
nsTArray<nsString> validEntryTypes;
for (const nsString& validTypeName : sValidTypeNames) {
if (aOptions.mEntryTypes.Contains<nsString>(validTypeName) &&
!validEntryTypes.Contains<nsString>(validTypeName)) {
validEntryTypes.AppendElement(validTypeName);
}
}
if (validEntryTypes.IsEmpty()) {
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return;
}
mEntryTypes = validEntryTypes;
mPerformance->AddObserver(this);
}
void
PerformanceObserver::Disconnect()
{
mPerformance->RemoveObserver(this);
}

View File

@ -0,0 +1,76 @@
/* -*- 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_PerformanceObserver_h__
#define mozilla_dom_PerformanceObserver_h__
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "mozilla/nsRefPtr.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
class nsPIDOMWindow;
class PerformanceBase;
namespace mozilla {
class ErrorResult;
namespace dom {
class GlobalObject;
class PerformanceEntry;
class PerformanceObserverCallback;
struct PerformanceObserverInit;
namespace workers {
class WorkerPrivate;
} // namespace workers
class PerformanceObserver final : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PerformanceObserver)
static already_AddRefed<PerformanceObserver>
Constructor(const GlobalObject& aGlobal,
PerformanceObserverCallback& aCb,
ErrorResult& aRv);
PerformanceObserver(nsPIDOMWindow* aOwner,
PerformanceObserverCallback& aCb);
PerformanceObserver(workers::WorkerPrivate* aWorkerPrivate,
PerformanceObserverCallback& aCb);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
nsISupports* GetParentObject() const { return mOwner; }
void Observe(const PerformanceObserverInit& aOptions,
mozilla::ErrorResult& aRv);
void Disconnect();
void Notify(PerformanceEntry* entry);
private:
~PerformanceObserver();
nsCOMPtr<nsISupports> mOwner;
nsRefPtr<PerformanceObserverCallback> mCallback;
nsRefPtr<PerformanceBase> mPerformance;
nsTArray<nsString> mEntryTypes;
};
} // namespace dom
} // namespace mozilla
#endif

View File

@ -0,0 +1,100 @@
/* -*- 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 "PerformanceObserverEntryList.h"
#include "mozilla/dom/PerformanceObserverEntryListBinding.h"
#include "nsPerformance.h"
#include "nsString.h"
#include "PerformanceResourceTiming.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceObserverEntryList,
mOwner,
mEntries)
NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceObserverEntryList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceObserverEntryList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceObserverEntryList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
PerformanceObserverEntryList::~PerformanceObserverEntryList()
{
}
JSObject*
PerformanceObserverEntryList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return PerformanceObserverEntryListBinding::Wrap(aCx, this, aGivenProto);
}
void
PerformanceObserverEntryList::GetEntries(
const PerformanceEntryFilterOptions& aFilter,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval)
{
aRetval.Clear();
for (const nsRefPtr<PerformanceEntry>& entry : mEntries) {
const PerformanceResourceTiming* resourceEntry =
entry->ToResourceTiming();
if (aFilter.mInitiatorType.WasPassed() && resourceEntry) {
nsAutoString initiatorType;
resourceEntry->GetInitiatorType(initiatorType);
if (!initiatorType.Equals(aFilter.mInitiatorType.Value())) {
continue;
}
}
if (aFilter.mName.WasPassed() &&
!entry->GetName().Equals(aFilter.mName.Value())) {
continue;
}
if (aFilter.mEntryType.WasPassed() &&
!entry->GetEntryType().Equals(aFilter.mEntryType.Value())) {
continue;
}
aRetval.AppendElement(entry);
}
}
void
PerformanceObserverEntryList::GetEntriesByType(
const nsAString& aEntryType,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval)
{
aRetval.Clear();
for (const nsRefPtr<PerformanceEntry>& entry : mEntries) {
if (entry->GetEntryType().Equals(aEntryType)) {
aRetval.AppendElement(entry);
}
}
}
void
PerformanceObserverEntryList::GetEntriesByName(
const nsAString& aName,
const Optional<nsAString>& aEntryType,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval)
{
aRetval.Clear();
for (const nsRefPtr<PerformanceEntry>& entry : mEntries) {
if (entry->GetName().Equals(aName)) {
aRetval.AppendElement(entry);
}
}
}
void
PerformanceObserverEntryList::AppendEntry(PerformanceEntry* aEntry)
{
mEntries.AppendElement(aEntry);
}

View File

@ -0,0 +1,64 @@
/* -*- 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_PerformanceObserverEntryList_h__
#define mozilla_dom_PerformanceObserverEntryList_h__
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/PerformanceEntryBinding.h"
namespace mozilla {
namespace dom {
struct PerformanceEntryFilterOptions;
class PerformanceEntry;
template<typename T> class Optional;
class PerformanceObserverEntryList final : public nsISupports,
public nsWrapperCache
{
~PerformanceObserverEntryList();
public:
explicit PerformanceObserverEntryList(nsISupports* aOwner)
: mOwner(aOwner)
{
}
nsISupports* GetParentObject() const
{
return mOwner;
}
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PerformanceObserverEntryList)
void GetEntries(const PerformanceEntryFilterOptions& aFilter,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
void GetEntriesByType(const nsAString& aEntryType,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
void GetEntriesByName(const nsAString& aName,
const Optional<nsAString>& aEntryType,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
void AppendEntry(PerformanceEntry* aEntry);
private:
nsCOMPtr<nsISupports> mOwner;
nsTArray<nsRefPtr<PerformanceEntry>> mEntries;
};
} // namespace dom
} // namespace mozilla
#endif

View File

@ -123,6 +123,11 @@ public:
return 0;
}
virtual const PerformanceResourceTiming* ToResourceTiming() const override
{
return this;
}
protected:
virtual ~PerformanceResourceTiming();

View File

@ -189,6 +189,8 @@ EXPORTS.mozilla.dom += [
'PerformanceEntry.h',
'PerformanceMark.h',
'PerformanceMeasure.h',
'PerformanceObserver.h',
'PerformanceObserverEntryList.h',
'PerformanceResourceTiming.h',
'ProcessGlobal.h',
'ResponsiveImageSelector.h',
@ -328,6 +330,8 @@ UNIFIED_SOURCES += [
'PerformanceEntry.cpp',
'PerformanceMark.cpp',
'PerformanceMeasure.cpp',
'PerformanceObserver.cpp',
'PerformanceObserverEntryList.cpp',
'PerformanceResourceTiming.cpp',
'PostMessageEvent.cpp',
'ProcessGlobal.cpp',

View File

@ -18,12 +18,14 @@
#include "PerformanceEntry.h"
#include "PerformanceMark.h"
#include "PerformanceMeasure.h"
#include "PerformanceObserver.h"
#include "PerformanceResourceTiming.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/PerformanceBinding.h"
#include "mozilla/dom/PerformanceEntryEvent.h"
#include "mozilla/dom/PerformanceTimingBinding.h"
#include "mozilla/dom/PerformanceNavigationBinding.h"
#include "mozilla/dom/PerformanceObserverBinding.h"
#include "mozilla/Preferences.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/TimeStamp.h"
@ -737,6 +739,25 @@ nsPerformance::IsEnabled(JSContext* aCx, JSObject* aGlobal)
return runnable->IsEnabled();
}
/* static */ bool
nsPerformance::IsObserverEnabled(JSContext* aCx, JSObject* aGlobal)
{
if (NS_IsMainThread()) {
return Preferences::GetBool("dom.enable_performance_observer", false);
}
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
nsRefPtr<PrefEnabledRunnable> runnable =
new PrefEnabledRunnable(workerPrivate,
NS_LITERAL_CSTRING("dom.enable_performance_observer"));
runnable->Dispatch(workerPrivate->GetJSContext());
return runnable->IsEnabled();
}
void
nsPerformance::InsertUserEntry(PerformanceEntry* aEntry)
{
@ -1028,6 +1049,10 @@ PerformanceBase::InsertUserEntry(PerformanceEntry* aEntry)
{
mUserEntries.InsertElementSorted(aEntry,
PerformanceEntryComparator());
NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers,
PerformanceObserver,
Notify, (aEntry));
}
void
@ -1051,4 +1076,19 @@ PerformanceBase::InsertResourceEntry(PerformanceEntry* aEntry)
// call onresourcetimingbufferfull
DispatchBufferFullEvent();
}
NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers,
PerformanceObserver,
Notify, (aEntry));
}
void
PerformanceBase::AddObserver(PerformanceObserver* aObserver)
{
mObservers.AppendElementUnlessExists(aObserver);
}
void
PerformanceBase::RemoveObserver(PerformanceObserver* aObserver)
{
mObservers.RemoveElement(aObserver);
}

View File

@ -26,6 +26,7 @@ namespace mozilla {
class ErrorResult;
namespace dom {
class PerformanceEntry;
class PerformanceObserver;
} // namespace dom
} // namespace mozilla
@ -300,6 +301,7 @@ public:
explicit PerformanceBase(nsPIDOMWindow* aWindow);
typedef mozilla::dom::PerformanceEntry PerformanceEntry;
typedef mozilla::dom::PerformanceObserver PerformanceObserver;
void GetEntries(nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
void GetEntriesByType(const nsAString& aEntryType,
@ -321,6 +323,9 @@ public:
void SetResourceTimingBufferSize(uint64_t aMaxSize);
void AddObserver(PerformanceObserver* aObserver);
void RemoveObserver(PerformanceObserver* aObserver);
protected:
virtual ~PerformanceBase();
@ -353,6 +358,8 @@ protected:
void LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const;
void TimingNotification(PerformanceEntry* aEntry, const nsACString& aOwner, uint64_t epoch);
nsTObserverArray<PerformanceObserver*> mObservers;
private:
nsTArray<nsRefPtr<PerformanceEntry>> mUserEntries;
nsTArray<nsRefPtr<PerformanceEntry>> mResourceEntries;
@ -376,6 +383,8 @@ public:
static bool IsEnabled(JSContext* aCx, JSObject* aGlobal);
static bool IsObserverEnabled(JSContext* aCx, JSObject* aGlobal);
nsDOMNavigationTiming* GetDOMTiming() const
{
return mDOMTiming;

View File

@ -247,6 +247,8 @@ support-files =
referrer_testserver.sjs
script_postmessages_fileList.js
iframe_postMessages.html
test_performance_observer.js
performance_observer.html
[test_anonymousContent_api.html]
[test_anonymousContent_append_after_reflow.html]
@ -805,6 +807,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
[test_window_define_nonconfigurable.html]
[test_root_iframe.html]
[test_performance_observer.html]
[test_performance_user_timing.html]
[test_bug1126851.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g'

View File

@ -0,0 +1,63 @@
<!--
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';
[
"async_test", "test", "setup",
"assert_true", "assert_equals", "assert_array_equals",
"assert_throws"
].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 promiseXHR(aUrl) {
return new Promise(resolve => {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onload = resolve;
xmlhttp.open("get", aUrl, true);
xmlhttp.send();
});
}
async_test(t => {
performance.clearResourceTimings();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['resource']});
assert_equals(observedEntries.length, 0);
promiseXHR("test-data.json").then(t.step_func_done(() => {
assert_equals(observedEntries.length, 1);
assert_array_equals(observedEntries,
performance.getEntriesByType("resource"),
"Observed 'resource' entries should equal to entries obtained by getEntriesByType.");
}));
}, "resource-timing test");
done();
</script>
</body>

View File

@ -0,0 +1,17 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<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>
<script>
'use strict';
SpecialPowers.pushPrefEnv({"set": [["dom.enable_performance_observer", true]]},
function() {
window.open("performance_observer.html");
});
</script>

View File

@ -0,0 +1,236 @@
setup({ explicit_done: true });
test(t => {
assert_throws({name: "TypeError"}, function() {
new PerformanceObserver();
}, "PerformanceObserver constructor should throw TypeError if no argument is specified.");
assert_throws({name: "TypeError"}, function() {
new PerformanceObserver({});
}, "PerformanceObserver constructor should throw TypeError if the argument is not a function.");
}, "Test that PerformanceObserver constructor throws exception");
test(t => {
var observer = new PerformanceObserver(() => {
});
assert_throws({name: "TypeError"}, function() {
observer.observe();
}, "observe() should throw TypeError exception if no option specified.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ unsupportedAttribute: "unsupported" });
}, "obsrve() should throw TypeError exception if the option has no 'entryTypes' attribute.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ entryTypes: [] });
}, "obsrve() should throw TypeError exception if 'entryTypes' attribute is an empty sequence.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ entryTypes: null });
}, "obsrve() should throw TypeError exception if 'entryTypes' attribute is null.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ entryTypes: ["invalid"]});
}, "obsrve() should throw TypeError exception if 'entryTypes' attribute value is invalid.");
}, "Test that PerformanceObserver.observe throws exception");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark', 'measure']});
assert_equals(observedEntries.length, 0,
"User timing entries should never be observed.");
assert_equals(performance.getEntriesByType("mark").length, 0,
"There should be no 'mark' entries.");
assert_equals(performance.getEntriesByType("measure").length, 0,
"There should be no 'measure' entries.");
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(observedEntries.length, 3,
"There should be three observed entries.");
var markEntries = observedEntries.filter(entry => {
return entry.entryType == "mark";
});
assert_array_equals(markEntries, performance.getEntriesByType("mark"),
"Observed 'mark' entries should equal to entries obtained by getEntriesByType.");
var measureEntries = observedEntries.filter(entry => {
return entry.entryType == "measure";
});
assert_array_equals(measureEntries, performance.getEntriesByType("measure"),
"Observed 'measure' entries should equal to entries obtained by getEntriesByType.");
}, "Test for user-timing with PerformanceObserver");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark', 'measure']});
observer.disconnect();
assert_equals(observedEntries.length, 0,
"User timing entries should be never observed.");
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(performance.getEntriesByType("mark").length, 2);
assert_equals(performance.getEntriesByType("measure").length, 1);
assert_equals(observedEntries.length, 0,
"User timing entries should be never observed after disconnecting observer.");
}, "Nothing should be notified after disconnecting observer");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntryList;
var observer = new PerformanceObserver(list => {
observedEntryList = list;
});
observer.observe({entryTypes: ['mark']});
performance.mark("test");
assert_array_equals(observedEntryList.getEntries({"entryType": "mark"}),
performance.getEntriesByType("mark"),
"getEntries with entryType filter should return correct results.");
assert_array_equals(observedEntryList.getEntries({"name": "test"}),
performance.getEntriesByName("test"),
"getEntries with name filter should return correct results.");
assert_array_equals(observedEntryList.getEntries({"name": "test",
"entryType": "mark"}),
performance.getEntriesByName("test"),
"getEntries with name and entryType filter should return correct results.");
assert_array_equals(observedEntryList.getEntries({"name": "invalid"}),
[],
"getEntries with non-existent name filter should return an empty array.");
assert_array_equals(observedEntryList.getEntries({"name": "test",
"entryType": "measure"}),
[],
"getEntries with name filter and non-existent entryType should return an empty array.");
assert_array_equals(observedEntryList.getEntries({"name": "invalid",
"entryType": "mark"}),
[],
"getEntries with non-existent name and entryType filter should return an empty array.");
}, "Test for PerformanceObserverEntryList.getEntries");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntryList;
var observer = new PerformanceObserver(list => {
observedEntryList = list;
});
observer.observe({entryTypes: ['mark', 'measure']});
performance.mark("test");
assert_array_equals(observedEntryList.getEntriesByType("mark"),
performance.getEntriesByType("mark"));
performance.measure("test-measure", "test", "test");
assert_array_equals(observedEntryList.getEntriesByType("measure"),
performance.getEntriesByType("measure"));
}, "Test for PerformanceObserverEntryList.getEntriesByType");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntryList;
var observer = new PerformanceObserver(list => {
observedEntryList = list;
});
observer.observe({entryTypes: ['mark', 'measure']});
performance.mark("test");
assert_array_equals(observedEntryList.getEntriesByName("test"),
performance.getEntriesByName("test"));
performance.measure("test-measure", "test", "test");
assert_array_equals(observedEntryList.getEntriesByName("test-measure"),
performance.getEntriesByName("test-measure"));
}, "Test for PerformanceObserverEntryList.getEntriesByName");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark', 'measure']});
observer.observe({entryTypes: ['mark', 'measure']});
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(observedEntries.length, 3,
"Observed user timing entries should have only three entries.");
}, "Test that invoking observe method twice affects nothing");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark', 'measure']});
observer.observe({entryTypes: ['mark']});
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(observedEntries.length, 2,
"Observed user timing entries should have only two entries.");
}, "Test that observing filter is replaced by a new filter");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark']});
observer.observe({entryTypes: ['measure']});
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(observedEntries.length, 1,
"Observed user timing entries should have only 1 entries.");
}, "Test that observing filter is replaced by a new filter");

View File

@ -71,3 +71,4 @@ partial interface Performance {
[Func="nsPerformance::IsEnabled"]
void clearMeasures(optional DOMString measureName);
};

View File

@ -0,0 +1,23 @@
/* -*- 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://w3c.github.io/performance-timeline/#the-performance-observer-interface
*/
dictionary PerformanceObserverInit {
required sequence<DOMString> entryTypes;
};
callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
[Func="nsPerformance::IsObserverEnabled",
Constructor(PerformanceObserverCallback callback),
Exposed=(Window,Worker)]
interface PerformanceObserver {
[Throws]
void observe(PerformanceObserverInit options);
void disconnect();
};

View File

@ -0,0 +1,24 @@
/* -*- 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://w3c.github.io/performance-timeline/#the-performanceobserverentrylist-interface
*/
// XXX should be moved into Performance.webidl.
dictionary PerformanceEntryFilterOptions {
DOMString name;
DOMString entryType;
DOMString initiatorType;
};
[Func="nsPerformance::IsObserverEnabled", Exposed=(Window,Worker)]
interface PerformanceObserverEntryList {
PerformanceEntryList getEntries(optional PerformanceEntryFilterOptions filter);
PerformanceEntryList getEntriesByType(DOMString entryType);
PerformanceEntryList getEntriesByName(DOMString name,
optional DOMString entryType);
};

View File

@ -353,6 +353,8 @@ WEBIDL_FILES = [
'PerformanceMark.webidl',
'PerformanceMeasure.webidl',
'PerformanceNavigation.webidl',
'PerformanceObserver.webidl',
'PerformanceObserverEntryList.webidl',
'PerformanceResourceTiming.webidl',
'PerformanceTiming.webidl',
'PeriodicWave.webidl',

View File

@ -106,8 +106,10 @@ support-files =
bug1132924_worker.js
empty.html
worker_performance_user_timing.js
worker_performance_observer.js
sharedworker_performance_user_timing.js
referrer.sjs
performance_observer.html
[test_404.html]
[test_atob.html]
@ -168,6 +170,7 @@ skip-if = buildapp == 'mulet'
[test_onLine.html]
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_performance_user_timing.html]
[test_performance_observer.html]
[test_promise.html]
[test_promise_resolved_with_string.html]
[test_recursion.html]

View File

@ -0,0 +1,32 @@
<!--
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>

View File

@ -0,0 +1,17 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<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>
<script>
'use strict';
SpecialPowers.pushPrefEnv({"set": [["dom.enable_performance_observer", true]]},
function() {
window.open("performance_observer.html");
});
</script>

View File

@ -0,0 +1,4 @@
importScripts(['/resources/testharness.js']);
importScripts(['../../../dom/base/test/test_performance_observer.js']);
done();