Implement PerformanceObserver
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Jan 2017 06:21:35 +0000 (06:21 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Jan 2017 06:21:35 +0000 (06:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=167546
<rdar://problem/30247959>

Reviewed by Ryosuke Niwa.

Source/JavaScriptCore:

* runtime/CommonIdentifiers.h:

Source/WebCore:

This implements PerformanceObserver from Performance Timeline Level 2:
https://w3c.github.io/performance-timeline/

Tests: performance-api/performance-observer-api.html
       performance-api/performance-observer-basic.html
       performance-api/performance-observer-callback-mutate.html
       performance-api/performance-observer-callback-task.html
       performance-api/performance-observer-entry-sort.html
       performance-api/performance-observer-exception.html
       performance-api/performance-observer-nested.html
       performance-api/performance-observer-order.html
       performance-api/performance-observer-periodic.html
       performance-api/performance-timeline-api.html

* CMakeLists.txt:
* DerivedSources.make:
* WebCore.xcodeproj/project.pbxproj:
New files.

* page/Performance.h:
* page/Performance.cpp:
(WebCore::Performance::mark):
(WebCore::Performance::measure):
(WebCore::Performance::registerPerformanceObserver):
(WebCore::Performance::unregisterPerformanceObserver):
(WebCore::Performance::queueEntry):
Register PerformanceObservers with the Performance object.
When new PerformanceEntries are created (Mark and Measure
right now) check them against observers.

* page/PerformanceEntry.cpp:
(WebCore::PerformanceEntry::PerformanceEntry):
(WebCore::PerformanceEntry::typeForEntryTypeString):
* page/PerformanceEntry.h:
(WebCore::PerformanceEntry::type):
Give PerformanceEntry a convenience enum for easy comparison
and to know if it is one of the built-in known types (which the
PerformanceObserver API takes into account).

* page/PerformanceObserver.cpp: Added.
(WebCore::PerformanceObserver::PerformanceObserver):
(WebCore::PerformanceObserver::observe):
(WebCore::PerformanceObserver::disconnect):
(WebCore::PerformanceObserver::queueEntry):
(WebCore::PerformanceObserver::deliver):
* page/PerformanceObserver.h:
(WebCore::PerformanceObserver::create):
(WebCore::PerformanceObserver::typeFilter):
- TypeErrors on observe bad behavior
- Completely replace types filter on observe
- Handle register and unregister
- Handle calling the callback

* page/PerformanceObserverCallback.idl: Added.
* page/PerformanceObserverEntryList.cpp: Added.
(WebCore::PerformanceObserverEntryList::PerformanceObserverEntryList):
(WebCore::PerformanceObserverEntryList::getEntries):
(WebCore::PerformanceObserverEntryList::getEntriesByType):
(WebCore::PerformanceObserverEntryList::getEntriesByName):
* page/PerformanceObserverEntryList.h:
(WebCore::PerformanceObserverEntryList::create):
* page/PerformanceObserverEntryList.idl: Added.
Implement sorting and filtering of entries.

* page/PerformanceObserver.idl: Added.
* page/PerformanceObserverCallback.h:
(WebCore::PerformanceObserverCallback::~PerformanceObserverCallback):
Mostly autogenerated.

* page/PerformanceUserTiming.cpp:
(WebCore::UserTiming::mark):
(WebCore::UserTiming::measure):
* page/PerformanceUserTiming.h:
Update these to return the entry so it can be passed on to
any interested PerformanceObservers.

Source/WebInspectorUI:

* UserInterface/Models/NativeFunctionParameters.js:
Improve API view display of built-in performance methods.

LayoutTests:

* performance-api/performance-observer-api-expected.txt: Added.
* performance-api/performance-observer-api.html: Added.
* performance-api/performance-observer-basic-expected.txt: Added.
* performance-api/performance-observer-basic.html: Added.
* performance-api/performance-observer-callback-mutate-expected.txt: Added.
* performance-api/performance-observer-callback-mutate.html: Added.
* performance-api/performance-observer-callback-task-expected.txt: Added.
* performance-api/performance-observer-callback-task.html: Added.
* performance-api/performance-observer-entry-sort-expected.txt: Added.
* performance-api/performance-observer-entry-sort.html: Added.
* performance-api/performance-observer-exception-expected.txt: Added.
* performance-api/performance-observer-exception.html: Added.
* performance-api/performance-observer-nested-expected.txt: Added.
* performance-api/performance-observer-nested.html: Added.
* performance-api/performance-observer-order-expected.txt: Added.
* performance-api/performance-observer-order.html: Added.
* performance-api/performance-observer-periodic-expected.txt: Added.
* performance-api/performance-observer-periodic.html: Added.
PerformanceObserver tests.

* performance-api/performance-timeline-api-expected.txt: Added.
* performance-api/performance-timeline-api.html: Added.
Performance timeline tests.

* platform/efl/js/dom/global-constructors-attributes-expected.txt:
* platform/gtk/js/dom/global-constructors-attributes-expected.txt:
* platform/mac-elcapitan/js/dom/global-constructors-attributes-expected.txt:
* platform/mac-wk1/js/dom/global-constructors-attributes-expected.txt:
* platform/mac-yosemite/js/dom/global-constructors-attributes-expected.txt:
* platform/mac/js/dom/global-constructors-attributes-expected.txt:
* platform/win/js/dom/global-constructors-attributes-expected.txt:
New global constructors.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@211406 268f45cc-cd09-0410-ab3c-d52691b4dbfc

56 files changed:
LayoutTests/ChangeLog
LayoutTests/performance-api/performance-observer-api-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-api.html [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-basic-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-basic.html [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-callback-mutate-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-callback-mutate.html [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-callback-task-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-callback-task.html [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-entry-sort-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-entry-sort.html [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-exception-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-exception.html [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-nested-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-nested.html [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-order-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-order.html [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-periodic-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-periodic.html [new file with mode: 0644]
LayoutTests/performance-api/performance-timeline-api-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-timeline-api.html [new file with mode: 0644]
LayoutTests/platform/efl/js/dom/global-constructors-attributes-expected.txt
LayoutTests/platform/gtk/js/dom/global-constructors-attributes-expected.txt
LayoutTests/platform/mac-elcapitan/js/dom/global-constructors-attributes-expected.txt
LayoutTests/platform/mac-wk1/js/dom/global-constructors-attributes-expected.txt
LayoutTests/platform/mac-yosemite/js/dom/global-constructors-attributes-expected.txt
LayoutTests/platform/mac/js/dom/global-constructors-attributes-expected.txt
LayoutTests/platform/win/js/dom/global-constructors-attributes-expected.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources.make
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/loader/cache/CachedResourceLoader.cpp
Source/WebCore/page/IntersectionObserver.h
Source/WebCore/page/Performance.cpp
Source/WebCore/page/Performance.h
Source/WebCore/page/PerformanceEntry.cpp
Source/WebCore/page/PerformanceEntry.h
Source/WebCore/page/PerformanceMark.h
Source/WebCore/page/PerformanceMeasure.h
Source/WebCore/page/PerformanceObserver.cpp [new file with mode: 0644]
Source/WebCore/page/PerformanceObserver.h [new file with mode: 0644]
Source/WebCore/page/PerformanceObserver.idl [new file with mode: 0644]
Source/WebCore/page/PerformanceObserverCallback.h [new file with mode: 0644]
Source/WebCore/page/PerformanceObserverCallback.idl [new file with mode: 0644]
Source/WebCore/page/PerformanceObserverEntryList.cpp [new file with mode: 0644]
Source/WebCore/page/PerformanceObserverEntryList.h [new file with mode: 0644]
Source/WebCore/page/PerformanceObserverEntryList.idl [new file with mode: 0644]
Source/WebCore/page/PerformanceResourceTiming.cpp
Source/WebCore/page/PerformanceUserTiming.cpp
Source/WebCore/page/PerformanceUserTiming.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Models/NativeFunctionParameters.js

index ea8cc90..8546261 100644 (file)
@@ -1,3 +1,44 @@
+2017-01-30  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Implement PerformanceObserver
+        https://bugs.webkit.org/show_bug.cgi?id=167546
+        <rdar://problem/30247959>
+
+        Reviewed by Ryosuke Niwa.
+
+        * performance-api/performance-observer-api-expected.txt: Added.
+        * performance-api/performance-observer-api.html: Added.
+        * performance-api/performance-observer-basic-expected.txt: Added.
+        * performance-api/performance-observer-basic.html: Added.
+        * performance-api/performance-observer-callback-mutate-expected.txt: Added.
+        * performance-api/performance-observer-callback-mutate.html: Added.
+        * performance-api/performance-observer-callback-task-expected.txt: Added.
+        * performance-api/performance-observer-callback-task.html: Added.
+        * performance-api/performance-observer-entry-sort-expected.txt: Added.
+        * performance-api/performance-observer-entry-sort.html: Added.
+        * performance-api/performance-observer-exception-expected.txt: Added.
+        * performance-api/performance-observer-exception.html: Added.
+        * performance-api/performance-observer-nested-expected.txt: Added.
+        * performance-api/performance-observer-nested.html: Added.
+        * performance-api/performance-observer-order-expected.txt: Added.
+        * performance-api/performance-observer-order.html: Added.
+        * performance-api/performance-observer-periodic-expected.txt: Added.
+        * performance-api/performance-observer-periodic.html: Added.
+        PerformanceObserver tests.
+
+        * performance-api/performance-timeline-api-expected.txt: Added.
+        * performance-api/performance-timeline-api.html: Added.
+        Performance timeline tests.
+
+        * platform/efl/js/dom/global-constructors-attributes-expected.txt:
+        * platform/gtk/js/dom/global-constructors-attributes-expected.txt:
+        * platform/mac-elcapitan/js/dom/global-constructors-attributes-expected.txt:
+        * platform/mac-wk1/js/dom/global-constructors-attributes-expected.txt:
+        * platform/mac-yosemite/js/dom/global-constructors-attributes-expected.txt:
+        * platform/mac/js/dom/global-constructors-attributes-expected.txt:
+        * platform/win/js/dom/global-constructors-attributes-expected.txt:
+        New global constructors.
+
 2017-01-30  Youenn Fablet  <youenn@apple.com>
 
         [WebRTC] getStats does not support legacy callback
diff --git a/LayoutTests/performance-api/performance-observer-api-expected.txt b/LayoutTests/performance-api/performance-observer-api-expected.txt
new file mode 100644 (file)
index 0000000..28efd87
--- /dev/null
@@ -0,0 +1,35 @@
+Basic Interface test for PerformanceObserver APIs.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PerformanceObserver
+PASS PerformanceObserver is defined.
+PASS PerformanceObserver.prototype.observe is defined.
+PASS PerformanceObserver.prototype.disconnect is defined.
+PASS PerformanceObserver() threw exception TypeError: Constructor requires 'new' operator.
+PASS new PerformanceObserver() threw exception TypeError: Not enough arguments.
+PASS new PerformanceObserver(1) threw exception TypeError: Argument 1 ('callback') to the PerformanceObserver constructor must be a function.
+PASS observer = new PerformanceObserver(function() {}) did not throw exception.
+PASS observer.observe() threw exception TypeError: Not enough arguments.
+PASS observer.observe("mark") threw exception TypeError: Type error.
+PASS observer.observe({}) threw exception TypeError: Member PerformanceObserverInit.entryTypes is required and must be an instance of sequence.
+PASS observer.observe({entryTypes:"mark"}) threw exception TypeError: Value is not a sequence.
+PASS observer.observe({entryTypes:[]}) threw exception TypeError: entryTypes cannot be an empty list.
+PASS observer.observe({entryTypes:["not-real"]}) threw exception TypeError: entryTypes contained only unsupported types.
+PASS observer.observe({entryTypes:["mark"]}) did not throw exception.
+PASS observer.observe({entryTypes:["mark", "not-real"]}) did not throw exception.
+PASS observer.observe({entryTypes:["mark", "measure"]}) did not throw exception.
+PASS observer.disconnect() did not throw exception.
+PASS observer.disconnect() did not throw exception.
+
+PerformanceObserverEntryList
+PASS PerformanceObserverEntryList is defined.
+PASS PerformanceObserverEntryList.prototype.getEntries is defined.
+PASS PerformanceObserverEntryList.prototype.getEntriesByType is defined.
+PASS PerformanceObserverEntryList.prototype.getEntriesByName is defined.
+PASS new PerformanceObserverEntryList() threw exception TypeError: function is not a constructor (evaluating 'new PerformanceObserverEntryList()').
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-observer-api.html b/LayoutTests/performance-api/performance-observer-api.html
new file mode 100644 (file)
index 0000000..648bc45
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Basic Interface test for PerformanceObserver APIs.");
+
+debug("PerformanceObserver");
+shouldBeDefined(`PerformanceObserver`);
+shouldBeDefined(`PerformanceObserver.prototype.observe`);
+shouldBeDefined(`PerformanceObserver.prototype.disconnect`);
+shouldThrow(`PerformanceObserver()`);
+shouldThrow(`new PerformanceObserver()`);
+shouldThrow(`new PerformanceObserver(1)`);
+shouldNotThrow(`observer = new PerformanceObserver(function() {})`);
+shouldThrow(`observer.observe()`);
+shouldThrow(`observer.observe("mark")`);
+shouldThrow(`observer.observe({})`);
+shouldThrow(`observer.observe({entryTypes:"mark"})`);
+shouldThrow(`observer.observe({entryTypes:[]})`);
+shouldThrow(`observer.observe({entryTypes:["not-real"]})`);
+shouldNotThrow(`observer.observe({entryTypes:["mark"]})`);
+shouldNotThrow(`observer.observe({entryTypes:["mark", "not-real"]})`);
+shouldNotThrow(`observer.observe({entryTypes:["mark", "measure"]})`);
+shouldNotThrow(`observer.disconnect()`);
+shouldNotThrow(`observer.disconnect()`);
+
+debug("");
+debug("PerformanceObserverEntryList");
+shouldBeDefined(`PerformanceObserverEntryList`);
+shouldBeDefined(`PerformanceObserverEntryList.prototype.getEntries`);
+shouldBeDefined(`PerformanceObserverEntryList.prototype.getEntriesByType`);
+shouldBeDefined(`PerformanceObserverEntryList.prototype.getEntriesByName`);
+shouldThrow(`new PerformanceObserverEntryList()`);
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-observer-basic-expected.txt b/LayoutTests/performance-api/performance-observer-basic-expected.txt
new file mode 100644 (file)
index 0000000..2b45ed7
--- /dev/null
@@ -0,0 +1,52 @@
+Basic Behavior test for PerformanceObserver APIs.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Inside PerformanceObserver callback
+PASS argumentsLength === 2 is true
+PASS list instanceof PerformanceObserverEntryList is true
+PASS obs instanceof PerformanceObserver is true
+PASS obs === observer is true
+FAIL thisObject instanceof PerformanceObserver should be true. Was false.
+FAIL thisObject === observer should be true. Was false.
+
+PerformanceObserverEntryList APIs
+PASS list.getEntries() instanceof Array is true
+PASS list.getEntries().length === 2 is true
+PASS list.getEntries()[0] instanceof PerformanceEntry is true
+PASS list.getEntries()[0].name is "mark3"
+PASS list.getEntries()[1].name is "mark4"
+PASS list.getEntries()[0].startTime <= list.getEntries()[1].startTime is true
+PASS list.getEntriesByType() threw exception TypeError: Not enough arguments.
+PASS list.getEntriesByType("not-real").length === 0 is true
+PASS list.getEntriesByType("mark").length === 2 is true
+PASS list.getEntriesByType("mark")[0] instanceof PerformanceEntry is true
+PASS list.getEntriesByType("mark")[0].name is "mark3"
+PASS list.getEntriesByType("mark")[1].name is "mark4"
+PASS list.getEntriesByName() threw exception TypeError: Not enough arguments.
+PASS list.getEntriesByName("not-real").length === 0 is true
+PASS list.getEntriesByName("mark1").length === 0 is true
+PASS list.getEntriesByName("mark3").length === 1 is true
+PASS list.getEntriesByName("mark3")[0] instanceof PerformanceEntry is true
+PASS list.getEntriesByName("mark3")[0].name is "mark3"
+PASS list.getEntriesByName("mark4").length === 1 is true
+PASS list.getEntriesByName("mark4")[0] instanceof PerformanceEntry is true
+PASS list.getEntriesByName("mark4")[0].name is "mark4"
+PASS list.getEntriesByName() threw exception TypeError: Not enough arguments.
+PASS list.getEntriesByName("not-real").length === 0 is true
+PASS list.getEntriesByName("mark1").length === 0 is true
+PASS list.getEntriesByName("mark3").length === 1 is true
+PASS list.getEntriesByName("mark3")[0] instanceof PerformanceEntry is true
+PASS list.getEntriesByName("mark3")[0].name is "mark3"
+PASS list.getEntriesByName("mark4").length === 1 is true
+PASS list.getEntriesByName("mark4")[0] instanceof PerformanceEntry is true
+PASS list.getEntriesByName("mark4")[0].name is "mark4"
+PASS list.getEntriesByName("mark3", "not-real").length === 0 is true
+PASS list.getEntriesByName("mark3", "mark").length === 1 is true
+PASS list.getEntriesByName(null, "mark").length === 0 is true
+PASS list.getEntriesByName(undefined, "mark").length === 0 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-observer-basic.html b/LayoutTests/performance-api/performance-observer-basic.html
new file mode 100644 (file)
index 0000000..6b0f6d6
--- /dev/null
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Basic Behavior test for PerformanceObserver APIs.");
+window.jsTestIsAsync = true;
+
+// PerformanceObservers that are not actively observing should not fire.
+let observerNotObserving = new PerformanceObserver(function() {
+    testFailed("PerformanceObserver never registered should not be called");
+});
+
+let observerNotObserving2 = new PerformanceObserver(function() {
+    testFailed("PerformanceObserver not actively observing should not be called");
+});
+observerNotObserving2.observe({entryTypes: ["mark"]});
+observerNotObserving2.disconnect();
+
+// PerformanceObservers for different entry types should not fire.
+let observerNotMarks = new PerformanceObserver(function() {
+    testFailed("PerformanceObserver observing measures should not be called");
+});
+
+// Observer sees marks while it is registered.
+performance.mark("mark1");
+window.observer = new PerformanceObserver(function(list, obs) {
+    window.argumentsLength = arguments.length;
+    window.list = list;
+    window.obs = obs;
+    window.thisObject = this;
+
+    debug("Inside PerformanceObserver callback");
+    shouldBeTrue(`argumentsLength === 2`);
+    shouldBeTrue(`list instanceof PerformanceObserverEntryList`);
+    shouldBeTrue(`obs instanceof PerformanceObserver`);
+    shouldBeTrue(`obs === observer`);
+    // FIXME: <https://webkit.org/b/167549> Invoking generated callback should allow setting the `this` object
+    shouldBeTrue(`thisObject instanceof PerformanceObserver`);
+    shouldBeTrue(`thisObject === observer`);
+
+    debug("");
+    debug("PerformanceObserverEntryList APIs");
+
+    shouldBeTrue(`list.getEntries() instanceof Array`);
+    shouldBeTrue(`list.getEntries().length === 2`);
+    shouldBeTrue(`list.getEntries()[0] instanceof PerformanceEntry`);
+    shouldBeEqualToString(`list.getEntries()[0].name`, "mark3");
+    shouldBeEqualToString(`list.getEntries()[1].name`, "mark4");
+    shouldBeTrue(`list.getEntries()[0].startTime <= list.getEntries()[1].startTime`);
+
+    shouldThrow(`list.getEntriesByType()`);
+    shouldBeTrue(`list.getEntriesByType("not-real").length === 0`);
+    shouldBeTrue(`list.getEntriesByType("mark").length === 2`);
+    shouldBeTrue(`list.getEntriesByType("mark")[0] instanceof PerformanceEntry`);
+    shouldBeEqualToString(`list.getEntriesByType("mark")[0].name`, "mark3");
+    shouldBeEqualToString(`list.getEntriesByType("mark")[1].name`, "mark4");
+
+    shouldThrow(`list.getEntriesByName()`);
+    shouldBeTrue(`list.getEntriesByName("not-real").length === 0`);
+    shouldBeTrue(`list.getEntriesByName("mark1").length === 0`);
+    shouldBeTrue(`list.getEntriesByName("mark3").length === 1`);
+    shouldBeTrue(`list.getEntriesByName("mark3")[0] instanceof PerformanceEntry`);
+    shouldBeEqualToString(`list.getEntriesByName("mark3")[0].name`, "mark3");
+    shouldBeTrue(`list.getEntriesByName("mark4").length === 1`);
+    shouldBeTrue(`list.getEntriesByName("mark4")[0] instanceof PerformanceEntry`);
+    shouldBeEqualToString(`list.getEntriesByName("mark4")[0].name`, "mark4");
+
+    shouldThrow(`list.getEntriesByName()`);
+    shouldBeTrue(`list.getEntriesByName("not-real").length === 0`);
+    shouldBeTrue(`list.getEntriesByName("mark1").length === 0`);
+    shouldBeTrue(`list.getEntriesByName("mark3").length === 1`);
+    shouldBeTrue(`list.getEntriesByName("mark3")[0] instanceof PerformanceEntry`);
+    shouldBeEqualToString(`list.getEntriesByName("mark3")[0].name`, "mark3");
+    shouldBeTrue(`list.getEntriesByName("mark4").length === 1`);
+    shouldBeTrue(`list.getEntriesByName("mark4")[0] instanceof PerformanceEntry`);
+    shouldBeEqualToString(`list.getEntriesByName("mark4")[0].name`, "mark4");
+
+    shouldBeTrue(`list.getEntriesByName("mark3", "not-real").length === 0`);
+    shouldBeTrue(`list.getEntriesByName("mark3", "mark").length === 1`);
+    shouldBeTrue(`list.getEntriesByName(null, "mark").length === 0`);
+    shouldBeTrue(`list.getEntriesByName(undefined, "mark").length === 0`);
+
+    finishJSTest();
+});
+performance.mark("mark2");
+observer.observe({entryTypes: ["mark"]});
+performance.mark("mark3");
+performance.mark("mark4");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-observer-callback-mutate-expected.txt b/LayoutTests/performance-api/performance-observer-callback-mutate-expected.txt
new file mode 100644 (file)
index 0000000..9ec540f
--- /dev/null
@@ -0,0 +1,42 @@
+Test PerformanceObserver mutating itself while in its callback.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Observering: ["measure"]
+PASS PerformanceObserver callback fired
+PASS list.getEntries().length is 1
+PASS list.getEntries()[0].entryType is "measure"
+PASS list.getEntries()[0].name is "measure1"
+Observering: ["mark"]
+ - measure1
+PASS PerformanceObserver callback fired
+PASS list.getEntries().length is 1
+PASS list.getEntries()[0].entryType is "mark"
+PASS list.getEntries()[0].name is "mark2"
+Observering: ["measure"]
+ - mark2
+PASS PerformanceObserver callback fired
+PASS list.getEntries().length is 2
+PASS list.getEntries()[0].entryType is "measure"
+PASS list.getEntries()[0].name is "measure3"
+PASS list.getEntries()[1].entryType is "mark"
+PASS list.getEntries()[1].name is "mark-before-change-observe-state-to-measure"
+Observering: ["mark","measure"]
+ - measure3
+ - mark-before-change-observe-state-to-measure
+PASS PerformanceObserver callback fired
+PASS list.getEntries().length is 3
+PASS list.getEntries()[0].entryType is "measure"
+PASS list.getEntries()[0].name is "measure-before-change-observe-state-to-both"
+PASS list.getEntries()[1].entryType is "measure"
+PASS list.getEntries()[1].name is "measure4"
+PASS list.getEntries()[2].entryType is "mark"
+PASS list.getEntries()[2].name is "mark4"
+ - measure-before-change-observe-state-to-both
+ - measure4
+ - mark4
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-observer-callback-mutate.html b/LayoutTests/performance-api/performance-observer-callback-mutate.html
new file mode 100644 (file)
index 0000000..f88eca4
--- /dev/null
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Test PerformanceObserver mutating itself while in its callback.");
+window.jsTestIsAsync = true;
+
+// Observer is first watching measures => then marks => measures => both.
+// NOTE: Measures are sorted before marks due to startTime.
+
+window.callbackCount = 0;
+window.list = null;
+
+let observer = new PerformanceObserver((list) => {
+    window.list = list;
+    callbackCount++;
+    testPassed("PerformanceObserver callback fired");
+
+    if (callbackCount === 1) {
+        // Expected: [measure1]
+        shouldBe(`list.getEntries().length`, `1`);
+        shouldBeEqualToString(`list.getEntries()[0].entryType`, "measure");
+        shouldBeEqualToString(`list.getEntries()[0].name`, "measure1");
+
+        updateObserver(["mark"]);
+
+        performance.mark("mark2");
+        performance.measure("measure2");
+    } else if (callbackCount === 2) {
+        // Expected: [mark2]
+        shouldBe(`list.getEntries().length`, `1`);
+        shouldBeEqualToString(`list.getEntries()[0].entryType`, "mark");
+        shouldBeEqualToString(`list.getEntries()[0].name`, "mark2");
+
+        performance.mark("mark-before-change-observe-state-to-measure");
+        performance.measure("measure-before-change-observe-state-to-measure");
+
+        updateObserver(["measure"]);
+
+        performance.mark("mark3");
+        performance.measure("measure3");
+    } else if (callbackCount === 3) {
+        // Expected: [measure3, mark-before-change-observe-state-to-measure]
+        shouldBe(`list.getEntries().length`, `2`);
+        shouldBeEqualToString(`list.getEntries()[0].entryType`, "measure");
+        shouldBeEqualToString(`list.getEntries()[0].name`, "measure3");
+        shouldBeEqualToString(`list.getEntries()[1].entryType`, "mark");
+        shouldBeEqualToString(`list.getEntries()[1].name`, "mark-before-change-observe-state-to-measure");
+
+        performance.mark("mark-before-change-observe-state-to-both");
+        performance.measure("measure-before-change-observe-state-to-both");
+
+        updateObserver(["mark", "measure"]);
+
+        performance.mark("mark4");
+        performance.measure("measure4");
+    } else if (callbackCount === 4) {
+        // Expected: [measure-before-change-observe-state-to-both, measure4, mark4]
+        shouldBe(`list.getEntries().length`, `3`);
+        shouldBeEqualToString(`list.getEntries()[0].entryType`, "measure");
+        shouldBeEqualToString(`list.getEntries()[0].name`, "measure-before-change-observe-state-to-both");
+        shouldBeEqualToString(`list.getEntries()[1].entryType`, "measure");
+        shouldBeEqualToString(`list.getEntries()[1].name`, "measure4");
+        shouldBeEqualToString(`list.getEntries()[2].entryType`, "mark");
+        shouldBeEqualToString(`list.getEntries()[2].name`, "mark4");
+
+        performance.mark("mark-before-disconnect");
+        performance.measure("measure-before-disconnect");
+
+        observer.disconnect();
+
+        performance.mark("mark-after-disconnect");
+        performance.measure("measure-after-disconnect");
+
+        setTimeout(finishJSTest, 50);
+    } else if (callbackCount === 5)
+        testFailed("Should not have received another callback, the observer was disconnected");
+
+    for (let mark of list.getEntries())
+        debug(" - " + mark.name);
+});
+
+function updateObserver(entryTypes) {
+    debug("Observering: " + JSON.stringify(entryTypes));
+    observer.observe({entryTypes});
+}
+
+updateObserver(["measure"]);
+performance.mark("mark1");
+performance.measure("measure1");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-observer-callback-task-expected.txt b/LayoutTests/performance-api/performance-observer-callback-task-expected.txt
new file mode 100644 (file)
index 0000000..203e3a0
--- /dev/null
@@ -0,0 +1,16 @@
+Test PerformanceObserver callback is a task, not a microtask.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS PerformanceObserver callback fired
+PASS microtaskExecuted is false
+PASS list.getEntries().length is 1
+PASS Promise microtask fired
+PASS PerformanceObserver callback fired
+PASS list.getEntries().length is 2
+PASS microtaskExecuted is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-observer-callback-task.html b/LayoutTests/performance-api/performance-observer-callback-task.html
new file mode 100644 (file)
index 0000000..616ea2f
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Test PerformanceObserver callback is a task, not a microtask.");
+window.jsTestIsAsync = true;
+
+window.microtaskExecuted = false;
+window.callbackCount = 0;
+window.list = null;
+
+let observer = new PerformanceObserver((list) => {
+    window.list = list;
+    callbackCount++;
+
+    testPassed("PerformanceObserver callback fired");
+
+    if (callbackCount === 1) {
+        shouldBeFalse(`microtaskExecuted`);
+        shouldBe(`list.getEntries().length`, `1`);
+        performance.mark("mark2");
+        Promise.resolve().then(() => {
+            testPassed("Promise microtask fired");
+            microtaskExecuted = true;
+            performance.mark("mark3");
+        });
+        return;
+    }
+
+    if (callbackCount === 2) {
+        shouldBe(`list.getEntries().length`, `2`);
+        shouldBeTrue(`microtaskExecuted`);
+        finishJSTest();
+        return;
+    }
+
+    testFailed("Callback should not have fired again");
+});
+
+observer.observe({entryTypes: ["mark"]});
+performance.mark("mark1");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-observer-entry-sort-expected.txt b/LayoutTests/performance-api/performance-observer-entry-sort-expected.txt
new file mode 100644 (file)
index 0000000..cbcbb41
--- /dev/null
@@ -0,0 +1,27 @@
+Test PerformanceObserver mutating itself while in its callback.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS PerformanceObserver callback fired
+PASS list.getEntries().length is 8
+PASS sorted is true
+PASS list.getEntries()[0].entryType is "measure"
+PASS list.getEntries()[1].entryType is "measure"
+PASS list.getEntries()[2].entryType is "measure"
+PASS list.getEntries()[3].entryType is "mark"
+PASS list.getEntries()[3].name is "mark1"
+PASS list.getEntries()[7].entryType is "mark"
+PASS list.getEntries()[7].name is "mark3"
+PASS list.getEntries()[0].name is "measure1"
+PASS list.getEntries()[1].name is "measure2"
+PASS list.getEntries()[2].name is "measure3"
+PASS list.getEntries()[3].name is "mark1"
+PASS list.getEntries()[4].name is "mark2"
+PASS list.getEntries()[5].name is "measure-matching-mark2-1"
+PASS list.getEntries()[6].name is "measure-matching-mark2-2"
+PASS list.getEntries()[7].name is "mark3"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-observer-entry-sort.html b/LayoutTests/performance-api/performance-observer-entry-sort.html
new file mode 100644 (file)
index 0000000..6eb1930
--- /dev/null
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Test PerformanceObserver mutating itself while in its callback.");
+window.jsTestIsAsync = true;
+
+function wait() {
+    let now = performance.now();
+    while (now === performance.now())
+        continue;
+}
+
+let observer = new PerformanceObserver((list) => {
+    testPassed("PerformanceObserver callback fired");
+
+    window.list = list;
+    window.sorted = true;
+
+    let entries = list.getEntries();
+    let lastStartTime = entries[0].startTime;
+    for (let i = 0; i < entries.length; ++i) {
+        let currentStartTime = entries[i].startTime;
+        if (lastStartTime > currentStartTime) {
+            sorted = false;
+            break;
+        }
+        lastStartTime = currentStartTime;
+    }
+
+    shouldBe(`list.getEntries().length`, `8`);
+    shouldBeTrue(`sorted`);
+
+    // Regardless of how identical start time elements are sorted,
+    // the first three values should be measures1,2,3 with 0 start time,
+    // followed by mark1. The last entry will be mark3.
+    shouldBeEqualToString(`list.getEntries()[0].entryType`, "measure");
+    shouldBeEqualToString(`list.getEntries()[1].entryType`, "measure");
+    shouldBeEqualToString(`list.getEntries()[2].entryType`, "measure");
+    shouldBeEqualToString(`list.getEntries()[3].entryType`, "mark");
+    shouldBeEqualToString(`list.getEntries()[3].name`, "mark1");
+    shouldBeEqualToString(`list.getEntries()[7].entryType`, "mark");
+    shouldBeEqualToString(`list.getEntries()[7].name`, "mark3");
+
+    // WebKit wants a stable sort based matching user expectations.
+    // The spec is currently imprecise here.
+    // <https://github.com/w3c/performance-timeline/issues/67>
+    shouldBeEqualToString(`list.getEntries()[0].name`, "measure1");
+    shouldBeEqualToString(`list.getEntries()[1].name`, "measure2");
+    shouldBeEqualToString(`list.getEntries()[2].name`, "measure3");
+    shouldBeEqualToString(`list.getEntries()[3].name`, "mark1");
+    shouldBeEqualToString(`list.getEntries()[4].name`, "mark2");
+    shouldBeEqualToString(`list.getEntries()[5].name`, "measure-matching-mark2-1");
+    shouldBeEqualToString(`list.getEntries()[6].name`, "measure-matching-mark2-2");
+    shouldBeEqualToString(`list.getEntries()[7].name`, "mark3");
+
+    finishJSTest();
+});
+
+observer.observe({entryTypes: ["mark", "measure"]});
+
+performance.mark("mark1");
+performance.measure("measure1");
+wait(); // Ensure mark1 !== mark2 startTime by making sure performance.now advances.
+performance.mark("mark2");
+performance.measure("measure2");
+performance.measure("measure-matching-mark2-1", "mark2");
+wait(); // Ensure mark2 !== mark3 startTime by making sure performance.now advances.
+performance.mark("mark3");
+performance.measure("measure3");
+performance.measure("measure-matching-mark2-2", "mark2");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-observer-exception-expected.txt b/LayoutTests/performance-api/performance-observer-exception-expected.txt
new file mode 100644 (file)
index 0000000..0e56362
--- /dev/null
@@ -0,0 +1,13 @@
+CONSOLE MESSAGE: line 23: EXCEPTION MESSAGE IN CALLBACK
+Ensure PerformanceObserver Exceptions are propogated.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PerformanceObserver callback fired
+PASS onerror: EXCEPTION MESSAGE IN CALLBACK
+PASS onerror: TypeError: Cannot call a class constructor without |new|
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-observer-exception.html b/LayoutTests/performance-api/performance-observer-exception.html
new file mode 100644 (file)
index 0000000..6a11cca
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Ensure PerformanceObserver Exceptions are propogated.");
+window.jsTestIsAsync = true;
+
+let seenExceptions = 0;
+
+window.onerror = function(message) {
+    testPassed("onerror: " + message);
+
+    seenExceptions++;
+    if (seenExceptions === 2)
+        finishJSTest();
+}
+
+let observer1 = new PerformanceObserver((list) => {
+    debug("PerformanceObserver callback fired");
+    throw "EXCEPTION MESSAGE IN CALLBACK";
+});
+
+class MyObserver {};
+let observer2 = new PerformanceObserver(MyObserver);
+
+observer1.observe({entryTypes: ["mark"]});
+observer2.observe({entryTypes: ["mark"]});
+performance.mark("mark1");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-observer-nested-expected.txt b/LayoutTests/performance-api/performance-observer-nested-expected.txt
new file mode 100644 (file)
index 0000000..ebfe056
--- /dev/null
@@ -0,0 +1,23 @@
+Test PerformanceObserver handling of entries added while in callback.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS PerformanceObserver 1 callback fired
+PASS list.getEntries().length is 1
+ - mark1
+PASS PerformanceObserver 2 callback fired
+PASS list.getEntries().length is 2
+ - mark1
+ - mark2
+PASS PerformanceObserver 1 callback fired
+PASS list.getEntries().length is 2
+ - mark2
+ - mark3
+PASS PerformanceObserver 2 callback fired
+PASS list.getEntries().length is 1
+ - mark3
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-observer-nested.html b/LayoutTests/performance-api/performance-observer-nested.html
new file mode 100644 (file)
index 0000000..6b8804f
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Test PerformanceObserver handling of entries added while in callback.");
+window.jsTestIsAsync = true;
+
+window.callbackCount = 0;
+window.list = null;
+
+let observer1 = new PerformanceObserver((list) => {
+    window.list = list;
+    callbackCount++;
+    testPassed("PerformanceObserver 1 callback fired");
+
+    if (callbackCount === 1) {
+        performance.mark("mark2");
+        shouldBe(`list.getEntries().length`, `1`);
+    } else if (callbackCount === 3) {
+        shouldBe(`list.getEntries().length`, `2`);
+    } else {
+        testFailed("Unexpected callback count");
+        finishJSTest();
+    }
+
+    for (let mark of list.getEntries())
+        debug(" - " + mark.name);
+});
+
+let observer2 = new PerformanceObserver((list) => {
+    window.list = list;
+    callbackCount++;
+    testPassed("PerformanceObserver 2 callback fired");
+
+    if (callbackCount === 2) {
+        performance.mark("mark3");
+        shouldBe(`list.getEntries().length`, `2`);
+    } else if (callbackCount === 4) {
+        shouldBe(`list.getEntries().length`, `1`);
+    } else {
+        testFailed("Unexpected callback count");
+        finishJSTest();
+    }
+
+    for (let mark of list.getEntries())
+        debug(" - " + mark.name);
+
+    if (callbackCount === 4)
+        finishJSTest();
+});
+
+observer1.observe({entryTypes: ["mark"]});
+observer2.observe({entryTypes: ["mark"]});
+performance.mark("mark1");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-observer-order-expected.txt b/LayoutTests/performance-api/performance-observer-order-expected.txt
new file mode 100644 (file)
index 0000000..9a114d2
--- /dev/null
@@ -0,0 +1,21 @@
+Ensure PerformanceObservers are notified in order of registration (observe).
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS PerformanceObserver 1 callback fired
+PASS count is 1
+PASS PerformanceObserver 2 callback fired
+PASS count is 2
+PASS PerformanceObserver 3 callback fired
+PASS count is 3
+PASS PerformanceObserver 4 callback fired
+PASS count is 4
+PASS PerformanceObserver 5 callback fired
+PASS count is 5
+PASS PerformanceObserver 6 callback fired
+PASS count is 6
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-observer-order.html b/LayoutTests/performance-api/performance-observer-order.html
new file mode 100644 (file)
index 0000000..45d26cd
--- /dev/null
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Ensure PerformanceObservers are notified in order of registration (observe).");
+window.jsTestIsAsync = true;
+
+window.count = 0;
+
+let observer1 = new PerformanceObserver((list) => {
+    count++;
+    testPassed("PerformanceObserver 1 callback fired");
+    shouldBe(`count`, `1`);
+});
+
+let observer2 = new PerformanceObserver((list) => {
+    count++;
+    testPassed("PerformanceObserver 2 callback fired");
+    shouldBe(`count`, `2`);
+});
+
+// Ensure creation doesn't impact order.
+let observerSpecial = new PerformanceObserver((list) => {
+    count++;
+    testPassed("PerformanceObserver 6 callback fired");
+    shouldBe(`count`, `6`);
+    finishJSTest();
+});
+
+let observer3 = new PerformanceObserver((list) => {
+    count++;
+    testPassed("PerformanceObserver 3 callback fired");
+    shouldBe(`count`, `3`);
+});
+
+let observer4 = new PerformanceObserver((list) => {
+    count++;
+    testPassed("PerformanceObserver 4 callback fired");
+    shouldBe(`count`, `4`);
+});
+
+let observer5 = new PerformanceObserver((list) => {
+    count++;
+    testPassed("PerformanceObserver 5 callback fired");
+    shouldBe(`count`, `5`);
+});
+
+// Register all in order.
+for (let o of [observer1, observer2, observerSpecial, observer3, observer4, observer5])
+    o.observe({entryTypes: ["mark"]});
+
+// Unregister and re-register moves this to the back of the line.
+observerSpecial.disconnect();
+observerSpecial.observe({entryTypes: ["mark"]});
+
+performance.mark("mark1");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-observer-periodic-expected.txt b/LayoutTests/performance-api/performance-observer-periodic-expected.txt
new file mode 100644 (file)
index 0000000..550fca6
--- /dev/null
@@ -0,0 +1,16 @@
+Ensure PerformanceObserver callback fires for all observed entries between observe/disconnect calls.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PerformanceObserver callback fired: 1 entries
+PASS mark1
+PerformanceObserver callback fired: 2 entries
+PASS mark2
+PASS mark3
+PerformanceObserver callback fired: 1 entries
+PASS mark7
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-observer-periodic.html b/LayoutTests/performance-api/performance-observer-periodic.html
new file mode 100644 (file)
index 0000000..38746b3
--- /dev/null
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Ensure PerformanceObserver callback fires for all observed entries between observe/disconnect calls.");
+window.jsTestIsAsync = true;
+
+let shouldEnd = false;
+
+let observer = new PerformanceObserver((list) => {
+    debug("PerformanceObserver callback fired: " + list.getEntries().length + " entries");
+    for (let mark of list.getEntries()) {
+        if (mark.name === "mark5" || mark.name === "mark6")
+            testFailed("Should not have observed " + mark.name);
+        else
+            testPassed(mark.name);
+    }
+    if (shouldEnd)
+        finishJSTest();
+});
+observer.observe({entryTypes: ["mark"]});
+
+// ---
+
+performance.mark("mark1");
+
+setTimeout(() => {
+    performance.mark("mark2");
+    performance.mark("mark3");
+}, 50);
+
+setTimeout(() => {
+    performance.mark("mark4");
+    observer.disconnect();
+    performance.mark("mark5"); // NOT seen.
+}, 100);
+
+setTimeout(() => {
+    performance.mark("mark6"); // NOT seen.
+    observer.observe({entryTypes: ["mark"]});
+    performance.mark("mark7");
+    shouldEnd = true;
+}, 150);
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-timeline-api-expected.txt b/LayoutTests/performance-api/performance-timeline-api-expected.txt
new file mode 100644 (file)
index 0000000..e3f2076
--- /dev/null
@@ -0,0 +1,48 @@
+Basic Interface test for performance-timeline APIs.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PerformanceEntry
+PASS PerformanceEntry is defined.
+PASS "name" in PerformanceEntry.prototype is true
+PASS "entryType" in PerformanceEntry.prototype is true
+PASS "startTime" in PerformanceEntry.prototype is true
+PASS "duration" in PerformanceEntry.prototype is true
+PASS new PerformanceEntry() threw exception TypeError: function is not a constructor (evaluating 'new PerformanceEntry()').
+
+Performance extensions
+PASS Performance.prototype.getEntries is defined.
+PASS Performance.prototype.getEntriesByType is defined.
+PASS Performance.prototype.getEntriesByName is defined.
+PASS performance.getEntries() instanceof Array is true
+PASS performance.getEntries().length === 0 is true
+PASS performance.mark("test"); did not throw exception.
+PASS performance.getEntries().length === 1 is true
+PASS performance.getEntries()[0] instanceof PerformanceEntry is true
+PASS performance.getEntries()[0].name is "test"
+PASS performance.getEntries()[0].entryType is "mark"
+PASS typeof performance.getEntries()[0].startTime === "number" is true
+PASS typeof performance.getEntries()[0].duration === "number" is true
+PASS performance.getEntriesByType() threw exception TypeError: Not enough arguments.
+PASS performance.getEntriesByType("not-real").length === 0 is true
+PASS performance.getEntriesByType("mark").length === 1 is true
+PASS performance.getEntriesByType("mark")[0] instanceof PerformanceEntry is true
+PASS performance.getEntriesByType("mark")[0].name is "test"
+PASS performance.getEntriesByType("mark")[0].entryType is "mark"
+PASS typeof performance.getEntriesByType("mark")[0].startTime === "number" is true
+PASS typeof performance.getEntriesByType("mark")[0].duration === "number" is true
+PASS performance.getEntriesByName() threw exception TypeError: Not enough arguments.
+PASS performance.getEntriesByName("not-real").length === 0 is true
+PASS performance.getEntriesByName("test").length === 1 is true
+PASS performance.getEntriesByName("test")[0] instanceof PerformanceEntry is true
+PASS performance.getEntriesByName("test")[0].name is "test"
+PASS performance.getEntriesByName("test")[0].entryType is "mark"
+PASS typeof performance.getEntriesByName("test")[0].startTime === "number" is true
+PASS typeof performance.getEntriesByName("test")[0].duration === "number" is true
+PASS performance.getEntriesByName("test", "not-real").length === 0 is true
+PASS performance.getEntriesByName("test", "mark").length === 1 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-timeline-api.html b/LayoutTests/performance-api/performance-timeline-api.html
new file mode 100644 (file)
index 0000000..e173919
--- /dev/null
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Basic Interface test for performance-timeline APIs.");
+
+debug("PerformanceEntry");
+shouldBeDefined("PerformanceEntry");
+shouldBeTrue(`"name" in PerformanceEntry.prototype`);
+shouldBeTrue(`"entryType" in PerformanceEntry.prototype`);
+shouldBeTrue(`"startTime" in PerformanceEntry.prototype`);
+shouldBeTrue(`"duration" in PerformanceEntry.prototype`);
+shouldThrow(`new PerformanceEntry()`);
+
+// NOTE: The APIs below may be going away. Replaced by PerformanceObserver.
+
+debug("");
+debug("Performance extensions");
+shouldBeDefined(`Performance.prototype.getEntries`);
+shouldBeDefined(`Performance.prototype.getEntriesByType`);
+shouldBeDefined(`Performance.prototype.getEntriesByName`);
+
+shouldBeTrue(`performance.getEntries() instanceof Array`);
+shouldBeTrue(`performance.getEntries().length === 0`);
+shouldNotThrow(`performance.mark("test");`);
+shouldBeTrue(`performance.getEntries().length === 1`);
+shouldBeTrue(`performance.getEntries()[0] instanceof PerformanceEntry`);
+shouldBeEqualToString(`performance.getEntries()[0].name`, "test");
+shouldBeEqualToString(`performance.getEntries()[0].entryType`, "mark");
+shouldBeTrue(`typeof performance.getEntries()[0].startTime === "number"`);
+shouldBeTrue(`typeof performance.getEntries()[0].duration === "number"`);
+
+shouldThrow(`performance.getEntriesByType()`);
+shouldBeTrue(`performance.getEntriesByType("not-real").length === 0`);
+shouldBeTrue(`performance.getEntriesByType("mark").length === 1`);
+shouldBeTrue(`performance.getEntriesByType("mark")[0] instanceof PerformanceEntry`);
+shouldBeEqualToString(`performance.getEntriesByType("mark")[0].name`, "test");
+shouldBeEqualToString(`performance.getEntriesByType("mark")[0].entryType`, "mark");
+shouldBeTrue(`typeof performance.getEntriesByType("mark")[0].startTime === "number"`);
+shouldBeTrue(`typeof performance.getEntriesByType("mark")[0].duration === "number"`);
+
+shouldThrow(`performance.getEntriesByName()`);
+shouldBeTrue(`performance.getEntriesByName("not-real").length === 0`);
+shouldBeTrue(`performance.getEntriesByName("test").length === 1`);
+shouldBeTrue(`performance.getEntriesByName("test")[0] instanceof PerformanceEntry`);
+shouldBeEqualToString(`performance.getEntriesByName("test")[0].name`, "test");
+shouldBeEqualToString(`performance.getEntriesByName("test")[0].entryType`, "mark");
+shouldBeTrue(`typeof performance.getEntriesByName("test")[0].startTime === "number"`);
+shouldBeTrue(`typeof performance.getEntriesByName("test")[0].duration === "number"`);
+shouldBeTrue(`performance.getEntriesByName("test", "not-real").length === 0`);
+shouldBeTrue(`performance.getEntriesByName("test", "mark").length === 1`);
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index a4aea0a..5ff00c2 100644 (file)
@@ -1028,6 +1028,16 @@ PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProp
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').value is PerformanceObserver
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').value is PerformanceObserverEntryList
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').value is PerformanceTiming
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('set') is false
index 52ad9fc..3e45877 100644 (file)
@@ -1158,6 +1158,16 @@ PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProp
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').value is PerformanceObserver
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').value is PerformanceObserverEntryList
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').value is PerformanceTiming
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('set') is false
index ab91b8e..7fc18ea 100644 (file)
@@ -1193,6 +1193,16 @@ PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProp
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').value is PerformanceObserver
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').value is PerformanceObserverEntryList
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').value is PerformanceTiming
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('set') is false
index ab91b8e..7fc18ea 100644 (file)
@@ -1193,6 +1193,16 @@ PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProp
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').value is PerformanceObserver
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').value is PerformanceObserverEntryList
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').value is PerformanceTiming
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('set') is false
index d517567..b081ad2 100644 (file)
@@ -1188,6 +1188,16 @@ PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProp
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').value is PerformanceObserver
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').value is PerformanceObserverEntryList
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').value is PerformanceTiming
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('set') is false
index d57e71c..aa80ee4 100644 (file)
@@ -1198,6 +1198,16 @@ PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProp
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').value is PerformanceObserver
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').value is PerformanceObserverEntryList
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').value is PerformanceTiming
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('set') is false
index 66aea2d..6e5de50 100644 (file)
@@ -888,6 +888,16 @@ PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProp
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceNavigation').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').value is PerformanceObserver
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').value is PerformanceObserverEntryList
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').value is PerformanceTiming
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'PerformanceTiming').hasOwnProperty('set') is false
index dac2018..a53a030 100644 (file)
@@ -1,3 +1,13 @@
+2017-01-30  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Implement PerformanceObserver
+        https://bugs.webkit.org/show_bug.cgi?id=167546
+        <rdar://problem/30247959>
+
+        Reviewed by Ryosuke Niwa.
+
+        * runtime/CommonIdentifiers.h:
+
 2017-01-30  Matt Baker  <mattbaker@apple.com>
 
         Web Inspector: Need some limit on Async Call Stacks for async loops (rAF loops)
index 455a412..5787af5 100644 (file)
@@ -89,6 +89,8 @@
     macro(PerformanceEntryList) \
     macro(PerformanceMark) \
     macro(PerformanceMeasure) \
+    macro(PerformanceObserver) \
+    macro(PerformanceObserverEntryList) \
     macro(PerformanceResourceTiming) \
     macro(Promise) \
     macro(Proxy) \
index 3ea503c..6b18daa 100644 (file)
@@ -601,6 +601,9 @@ set(WebCore_NON_SVG_IDL_FILES
     page/PerformanceEntry.idl
     page/PerformanceMark.idl
     page/PerformanceMeasure.idl
+    page/PerformanceObserver.idl
+    page/PerformanceObserverCallback.idl
+    page/PerformanceObserverEntryList.idl
     page/PerformanceNavigation.idl
     page/PerformanceResourceTiming.idl
     page/PerformanceTiming.idl
@@ -1993,6 +1996,8 @@ set(WebCore_SOURCES
     page/PerformanceLogging.cpp
     page/PerformanceMonitor.cpp
     page/PerformanceNavigation.cpp
+    page/PerformanceObserver.cpp
+    page/PerformanceObserverEntryList.cpp
     page/PerformanceResourceTiming.cpp
     page/PerformanceTiming.cpp
     page/PerformanceUserTiming.cpp
index c87153c..33f0bfe 100644 (file)
@@ -1,3 +1,87 @@
+2017-01-30  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Implement PerformanceObserver
+        https://bugs.webkit.org/show_bug.cgi?id=167546
+        <rdar://problem/30247959>
+
+        Reviewed by Ryosuke Niwa.
+
+        This implements PerformanceObserver from Performance Timeline Level 2:
+        https://w3c.github.io/performance-timeline/
+
+        Tests: performance-api/performance-observer-api.html
+               performance-api/performance-observer-basic.html
+               performance-api/performance-observer-callback-mutate.html
+               performance-api/performance-observer-callback-task.html
+               performance-api/performance-observer-entry-sort.html
+               performance-api/performance-observer-exception.html
+               performance-api/performance-observer-nested.html
+               performance-api/performance-observer-order.html
+               performance-api/performance-observer-periodic.html
+               performance-api/performance-timeline-api.html
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * WebCore.xcodeproj/project.pbxproj:
+        New files.
+
+        * page/Performance.h:
+        * page/Performance.cpp:
+        (WebCore::Performance::mark):
+        (WebCore::Performance::measure):
+        (WebCore::Performance::registerPerformanceObserver):
+        (WebCore::Performance::unregisterPerformanceObserver):
+        (WebCore::Performance::queueEntry):
+        Register PerformanceObservers with the Performance object.
+        When new PerformanceEntries are created (Mark and Measure
+        right now) check them against observers.
+
+        * page/PerformanceEntry.cpp:
+        (WebCore::PerformanceEntry::PerformanceEntry):
+        (WebCore::PerformanceEntry::typeForEntryTypeString):
+        * page/PerformanceEntry.h:
+        (WebCore::PerformanceEntry::type):
+        Give PerformanceEntry a convenience enum for easy comparison
+        and to know if it is one of the built-in known types (which the
+        PerformanceObserver API takes into account).
+
+        * page/PerformanceObserver.cpp: Added.
+        (WebCore::PerformanceObserver::PerformanceObserver):
+        (WebCore::PerformanceObserver::observe):
+        (WebCore::PerformanceObserver::disconnect):
+        (WebCore::PerformanceObserver::queueEntry):
+        (WebCore::PerformanceObserver::deliver):
+        * page/PerformanceObserver.h:
+        (WebCore::PerformanceObserver::create):
+        (WebCore::PerformanceObserver::typeFilter):
+        - TypeErrors on observe bad behavior
+        - Completely replace types filter on observe
+        - Handle register and unregister
+        - Handle calling the callback
+
+        * page/PerformanceObserverCallback.idl: Added.
+        * page/PerformanceObserverEntryList.cpp: Added.
+        (WebCore::PerformanceObserverEntryList::PerformanceObserverEntryList):
+        (WebCore::PerformanceObserverEntryList::getEntries):
+        (WebCore::PerformanceObserverEntryList::getEntriesByType):
+        (WebCore::PerformanceObserverEntryList::getEntriesByName):
+        * page/PerformanceObserverEntryList.h:
+        (WebCore::PerformanceObserverEntryList::create):
+        * page/PerformanceObserverEntryList.idl: Added.
+        Implement sorting and filtering of entries.
+
+        * page/PerformanceObserver.idl: Added.
+        * page/PerformanceObserverCallback.h:
+        (WebCore::PerformanceObserverCallback::~PerformanceObserverCallback):
+        Mostly autogenerated.
+
+        * page/PerformanceUserTiming.cpp:
+        (WebCore::UserTiming::mark):
+        (WebCore::UserTiming::measure):
+        * page/PerformanceUserTiming.h:
+        Update these to return the entry so it can be passed on to
+        any interested PerformanceObservers.
+
 2017-01-30  Youenn Fablet  <youenn@apple.com>
 
         [WebRTC] getStats does not support legacy callback
index 38e7cb9..71066c6 100644 (file)
@@ -584,6 +584,9 @@ JS_BINDING_IDLS = \
     $(WebCore)/page/PerformanceMark.idl \
     $(WebCore)/page/PerformanceMeasure.idl \
     $(WebCore)/page/PerformanceNavigation.idl \
+    $(WebCore)/page/PerformanceObserver.idl \
+    $(WebCore)/page/PerformanceObserverCallback.idl \
+    $(WebCore)/page/PerformanceObserverEntryList.idl \
     $(WebCore)/page/PerformanceResourceTiming.idl \
     $(WebCore)/page/PerformanceTiming.idl \
     $(WebCore)/page/Screen.idl \
index 2c98d48..6f904ed 100644 (file)
                A5A2AF0B1829734300DE1729 /* PageDebuggable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5A2AF091829734300DE1729 /* PageDebuggable.cpp */; };
                A5A2AF0C1829734300DE1729 /* PageDebuggable.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A2AF0A1829734300DE1729 /* PageDebuggable.h */; };
                A5A7AA43132F0ECC00D3A3C2 /* AutocapitalizeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A7AA42132F0ECC00D3A3C2 /* AutocapitalizeTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               A5A9933D1E37FB19005B5E4D /* PerformanceObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A993361E37FAFD005B5E4D /* PerformanceObserver.h */; };
+               A5A9933E1E37FB1C005B5E4D /* PerformanceObserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5A993351E37FAFD005B5E4D /* PerformanceObserver.cpp */; };
+               A5A9933F1E37FB1F005B5E4D /* PerformanceObserverCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A993381E37FAFD005B5E4D /* PerformanceObserverCallback.h */; };
+               A5A993401E37FB25005B5E4D /* PerformanceObserverEntryList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5A9933A1E37FAFD005B5E4D /* PerformanceObserverEntryList.cpp */; };
+               A5A993411E37FB28005B5E4D /* PerformanceObserverEntryList.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A9933B1E37FAFD005B5E4D /* PerformanceObserverEntryList.h */; };
+               A5A993481E3809C6005B5E4D /* JSPerformanceObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A993431E380999005B5E4D /* JSPerformanceObserver.h */; };
+               A5A993491E3809C9005B5E4D /* JSPerformanceObserverCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5A993441E380999005B5E4D /* JSPerformanceObserverCallback.cpp */; };
+               A5A9934A1E3809CB005B5E4D /* JSPerformanceObserverCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A993451E380999005B5E4D /* JSPerformanceObserverCallback.h */; };
+               A5A9934B1E3809CD005B5E4D /* JSPerformanceObserverEntryList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5A993461E380999005B5E4D /* JSPerformanceObserverEntryList.cpp */; };
+               A5A9934C1E3809CF005B5E4D /* JSPerformanceObserverEntryList.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A993471E380999005B5E4D /* JSPerformanceObserverEntryList.h */; };
+               A5A9934D1E3809D7005B5E4D /* JSPerformanceObserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5A993421E380999005B5E4D /* JSPerformanceObserver.cpp */; };
                A5AFB34F115151A700B045CB /* StepRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5AFB34D115151A700B045CB /* StepRange.cpp */; };
                A5AFB350115151A700B045CB /* StepRange.h in Headers */ = {isa = PBXBuildFile; fileRef = A5AFB34E115151A700B045CB /* StepRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A5DEBDA316FB908700836FE0 /* WebKitPlaybackTargetAvailabilityEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DEBD9F16FB908700836FE0 /* WebKitPlaybackTargetAvailabilityEvent.cpp */; };
                A5A2AF091829734300DE1729 /* PageDebuggable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageDebuggable.cpp; sourceTree = "<group>"; };
                A5A2AF0A1829734300DE1729 /* PageDebuggable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageDebuggable.h; sourceTree = "<group>"; };
                A5A7AA42132F0ECC00D3A3C2 /* AutocapitalizeTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutocapitalizeTypes.h; sourceTree = "<group>"; };
+               A5A993351E37FAFD005B5E4D /* PerformanceObserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PerformanceObserver.cpp; sourceTree = "<group>"; };
+               A5A993361E37FAFD005B5E4D /* PerformanceObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PerformanceObserver.h; sourceTree = "<group>"; };
+               A5A993371E37FAFD005B5E4D /* PerformanceObserver.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PerformanceObserver.idl; sourceTree = "<group>"; };
+               A5A993381E37FAFD005B5E4D /* PerformanceObserverCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PerformanceObserverCallback.h; sourceTree = "<group>"; };
+               A5A993391E37FAFD005B5E4D /* PerformanceObserverCallback.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PerformanceObserverCallback.idl; sourceTree = "<group>"; };
+               A5A9933A1E37FAFD005B5E4D /* PerformanceObserverEntryList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PerformanceObserverEntryList.cpp; sourceTree = "<group>"; };
+               A5A9933B1E37FAFD005B5E4D /* PerformanceObserverEntryList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PerformanceObserverEntryList.h; sourceTree = "<group>"; };
+               A5A9933C1E37FAFD005B5E4D /* PerformanceObserverEntryList.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PerformanceObserverEntryList.idl; sourceTree = "<group>"; };
+               A5A993421E380999005B5E4D /* JSPerformanceObserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPerformanceObserver.cpp; sourceTree = "<group>"; };
+               A5A993431E380999005B5E4D /* JSPerformanceObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPerformanceObserver.h; sourceTree = "<group>"; };
+               A5A993441E380999005B5E4D /* JSPerformanceObserverCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPerformanceObserverCallback.cpp; sourceTree = "<group>"; };
+               A5A993451E380999005B5E4D /* JSPerformanceObserverCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPerformanceObserverCallback.h; sourceTree = "<group>"; };
+               A5A993461E380999005B5E4D /* JSPerformanceObserverEntryList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPerformanceObserverEntryList.cpp; sourceTree = "<group>"; };
+               A5A993471E380999005B5E4D /* JSPerformanceObserverEntryList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPerformanceObserverEntryList.h; sourceTree = "<group>"; };
                A5AFB34D115151A700B045CB /* StepRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StepRange.cpp; sourceTree = "<group>"; };
                A5AFB34E115151A700B045CB /* StepRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StepRange.h; sourceTree = "<group>"; };
                A5C974CF11485FF10066F2AB /* KeyEventCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyEventCocoa.h; sourceTree = "<group>"; };
                                0744ECEC1E0C4AE5000D0944 /* MockRealtimeAudioSourceMac.mm */,
                                07EE76ED1BEA619800F89133 /* MockRealtimeVideoSourceMac.h */,
                                07EE76EE1BEA619800F89133 /* MockRealtimeVideoSourceMac.mm */,
+                               41103AAA1E39790A00769F03 /* RealtimeIncomingAudioSource.cpp */,
+                               41103AA91E39790A00769F03 /* RealtimeIncomingAudioSource.h */,
                                4A0FFAA31AAF5EF60062803B /* RealtimeMediaSourceCenterMac.cpp */,
                                4A0FFAA41AAF5EF60062803B /* RealtimeMediaSourceCenterMac.h */,
                                41103AA71E39790A00769F03 /* RealtimeOutgoingAudioSource.cpp */,
                                41103AA81E39790A00769F03 /* RealtimeOutgoingAudioSource.h */,
-                               41103AA91E39790A00769F03 /* RealtimeIncomingAudioSource.h */,
-                               41103AAA1E39790A00769F03 /* RealtimeIncomingAudioSource.cpp */,
                                07D6373E1BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.h */,
                                07D6373F1BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.mm */,
                        );
                                51058AD81D679257009A538C /* MockGamepad.h */,
                                51058AD91D679257009A538C /* MockGamepadProvider.cpp */,
                                51058ADA1D679257009A538C /* MockGamepadProvider.h */,
-                               4157EBF81E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.h */,
                                4157EBF91E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.cpp */,
+                               4157EBF81E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.h */,
                                2D6F3E8A1C1ECB1C0061DBD4 /* MockPageOverlay.cpp */,
                                2D6F3E8B1C1ECB1C0061DBD4 /* MockPageOverlay.h */,
                                2D6F3E8C1C1ECB1C0061DBD4 /* MockPageOverlay.idl */,
                                8AF4E55211DC5A36000ED3DE /* PerformanceNavigation.cpp */,
                                8AF4E55311DC5A36000ED3DE /* PerformanceNavigation.h */,
                                8AF4E55411DC5A36000ED3DE /* PerformanceNavigation.idl */,
+                               A5A993351E37FAFD005B5E4D /* PerformanceObserver.cpp */,
+                               A5A993361E37FAFD005B5E4D /* PerformanceObserver.h */,
+                               A5A993371E37FAFD005B5E4D /* PerformanceObserver.idl */,
+                               A5A993381E37FAFD005B5E4D /* PerformanceObserverCallback.h */,
+                               A5A993391E37FAFD005B5E4D /* PerformanceObserverCallback.idl */,
+                               A5A9933A1E37FAFD005B5E4D /* PerformanceObserverEntryList.cpp */,
+                               A5A9933B1E37FAFD005B5E4D /* PerformanceObserverEntryList.h */,
+                               A5A9933C1E37FAFD005B5E4D /* PerformanceObserverEntryList.idl */,
                                86512EDB154A2AEE00A90426 /* PerformanceResourceTiming.cpp */,
                                86512EDC154A2AEF00A90426 /* PerformanceResourceTiming.h */,
                                86512EDD154A2AEF00A90426 /* PerformanceResourceTiming.idl */,
                A59E3C1B11580F340072928E /* ios */ = {
                        isa = PBXGroup;
                        children = (
-                               F48223121E386E240066FC79 /* AbstractPasteboard.h */,
                                A148328B187F506800DA63A6 /* wak */,
+                               F48223121E386E240066FC79 /* AbstractPasteboard.h */,
                                2655414B1489AA2B000DFC5D /* CursorIOS.cpp */,
                                A1ED778A1BE3293F00DC1791 /* Device.cpp */,
                                A1ED778B1BE3294000DC1791 /* Device.h */,
                                E45390380EAFD637003695C8 /* WebCoreSystemInterfaceIOS.mm */,
                                FE0D84E810484348001A179E /* WebEvent.h */,
                                FE0D84EA1048436E001A179E /* WebEvent.mm */,
+                               F482230F1E3869B80066FC79 /* WebItemProviderPasteboard.h */,
+                               F482230E1E3869B80066FC79 /* WebItemProviderPasteboard.mm */,
                                CDA29A2E1CBF73FC00901CCF /* WebPlaybackSessionInterfaceAVKit.h */,
                                CDA29A2F1CBF73FC00901CCF /* WebPlaybackSessionInterfaceAVKit.mm */,
                                3F42B31B1881191B00278AAC /* WebVideoFullscreenControllerAVKit.h */,
                                3FBC4AF2189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.h */,
                                3FBC4AF1189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.mm */,
                                E453903C0EAFD637003695C8 /* WidgetIOS.mm */,
-                               F482230E1E3869B80066FC79 /* WebItemProviderPasteboard.mm */,
-                               F482230F1E3869B80066FC79 /* WebItemProviderPasteboard.h */,
                        );
                        path = ios;
                        sourceTree = "<group>";
                                A58C59CF1E382EA90047859C /* JSPerformanceMeasure.h */,
                                8A9A586E11E84C35008ACFD1 /* JSPerformanceNavigation.cpp */,
                                8A9A586F11E84C36008ACFD1 /* JSPerformanceNavigation.h */,
+                               A5A993421E380999005B5E4D /* JSPerformanceObserver.cpp */,
+                               A5A993431E380999005B5E4D /* JSPerformanceObserver.h */,
+                               A5A993441E380999005B5E4D /* JSPerformanceObserverCallback.cpp */,
+                               A5A993451E380999005B5E4D /* JSPerformanceObserverCallback.h */,
+                               A5A993461E380999005B5E4D /* JSPerformanceObserverEntryList.cpp */,
+                               A5A993471E380999005B5E4D /* JSPerformanceObserverEntryList.h */,
                                CB38FD581CD2314500592A3F /* JSPerformanceResourceTiming.cpp */,
                                CB38FD591CD2314500592A3F /* JSPerformanceResourceTiming.h */,
                                0F43C85E189E15A600019AE2 /* JSPerformanceTiming.cpp */,
                                A1B5B29F1AAA846F008B6042 /* MockContentFilterSettings.h in Headers */,
                                51058ADC1D6792C1009A538C /* MockGamepad.h in Headers */,
                                51058ADE1D6792C1009A538C /* MockGamepadProvider.h in Headers */,
+                               4157EBFB1E3AB67F00AC9FE9 /* MockLibWebRTCPeerConnection.h in Headers */,
                                2D6F3E911C1ECB2F0061DBD4 /* MockPageOverlay.h in Headers */,
                                2D97F04819DD4140001EE9C3 /* MockPageOverlayClient.h in Headers */,
                                A140618C1E2ECA0A0032B34E /* MockQuickLookHandleClient.h in Headers */,
                                AA5F3B8D16CC33D100455EB0 /* PlatformSpeechSynthesizerMock.h in Headers */,
                                A1763F3F1E205234001D58DE /* WebArchiveDumpSupport.h in Headers */,
                                41815C1F138319830057AAA4 /* WebCoreTestSupport.h in Headers */,
-                               4157EBFB1E3AB67F00AC9FE9 /* MockLibWebRTCPeerConnection.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               F48223131E386E240066FC79 /* AbstractPasteboard.h in Headers */,
                                41E1B1D10FF5986900576B3B /* AbstractWorker.h in Headers */,
                                29A8122E0FBB9C1D00510293 /* AccessibilityARIAGridCell.h in Headers */,
                                29A812330FBB9C1D00510293 /* AccessibilityARIAGridRow.h in Headers */,
                                319848011A1D817B00A13318 /* AnimationEvent.h in Headers */,
                                49E912AD0EFAC906009D0CAF /* AnimationList.h in Headers */,
                                31DCD29D1AB4FBDE0072E817 /* AnimationTrigger.h in Headers */,
-                               417612B01E3A994000C3D81D /* LibWebRTCMediaEndpoint.h in Headers */,
                                0F580FAF149800D400FB5BD8 /* AnimationUtilities.h in Headers */,
                                93309DD7099E64920056E581 /* AppendNodeCommand.h in Headers */,
                                7C6579E31E00827000E3A27A /* ApplePayLineItem.h in Headers */,
                                CE799FA81C6A50570097B518 /* ContentSecurityPolicyMediaListDirective.h in Headers */,
                                CE6DADFA1C591E6A003F6A88 /* ContentSecurityPolicyResponseHeaders.h in Headers */,
                                CE799FA01C6A4C160097B518 /* ContentSecurityPolicySource.h in Headers */,
-                               F48223131E386E240066FC79 /* AbstractPasteboard.h in Headers */,
                                CE799F981C6A46BC0097B518 /* ContentSecurityPolicySourceList.h in Headers */,
                                CE799FAC1C6A50660097B518 /* ContentSecurityPolicySourceListDirective.h in Headers */,
                                41D015CA0F4B5C71004A662F /* ContentType.h in Headers */,
                                085B92BB0EFDE73D00E6123C /* FormDataBuilder.h in Headers */,
                                A8136D380973A8E700D74463 /* FormDataList.h in Headers */,
                                7EE6846712D26E3800E79415 /* FormDataStreamCFNet.h in Headers */,
-                               4157474A1E3869AD00E914D8 /* LibWebRTCUtils.h in Headers */,
                                514C764E0CE9234E007EF3CD /* FormDataStreamMac.h in Headers */,
                                9B50B1DE17CD4C0F0087F63C /* FormNamedItem.h in Headers */,
                                656D373A0ADBA5DE00A4554D /* FormState.h in Headers */,
                                A80D67080E9E9DEB00E420F0 /* GraphicsContextPlatformPrivateCG.h in Headers */,
                                0F580B0D0F12A2690051D689 /* GraphicsLayer.h in Headers */,
                                499B3ED7128CD31400E726C2 /* GraphicsLayerCA.h in Headers */,
-                               41103AAD1E39791000769F03 /* RealtimeIncomingAudioSource.h in Headers */,
                                0F580B0E0F12A2690051D689 /* GraphicsLayerClient.h in Headers */,
                                1AC69593161A1E53003732CB /* GraphicsLayerFactory.h in Headers */,
                                0FA24D7A162DF91900A3F4C0 /* GraphicsLayerUpdater.h in Headers */,
                                26EA89A71B4F2B75008C5FD2 /* HashableActionList.h in Headers */,
                                8482B7461198C35400BFB005 /* HashChangeEvent.h in Headers */,
                                A8748BE012CBF2DC001FBA41 /* HashTools.h in Headers */,
-                               E3E4E2A81E3B17100023BB8A /* ScriptElementCachedScriptFetcher.h in Headers */,
                                F55B3DC01251F12D003EF269 /* HiddenInputType.h in Headers */,
                                515BE19C1D54F6C100DD7C68 /* HIDGamepad.h in Headers */,
                                515BE19E1D54F6C100DD7C68 /* HIDGamepadProvider.h in Headers */,
                                4969B0F313D0B33F00DF3521 /* HitTestingTransformState.h in Headers */,
                                2D8287F716E4A0380086BD00 /* HitTestLocation.h in Headers */,
                                930908910AF7EDE40081DF01 /* HitTestRequest.h in Headers */,
-                               415747471E3869A400E914D8 /* LibWebRTCMacros.h in Headers */,
                                9307F1D80AF2D59000DBA31A /* HitTestResult.h in Headers */,
                                BC3BC29C0E91AB0F00835588 /* HostWindow.h in Headers */,
                                FD31609912B026F700C1A359 /* HRTFDatabase.h in Headers */,
                                A58C59D11E382EAE0047859C /* JSPerformanceMark.h in Headers */,
                                A58C59D31E382EB20047859C /* JSPerformanceMeasure.h in Headers */,
                                8A9A587111E84C36008ACFD1 /* JSPerformanceNavigation.h in Headers */,
+                               A5A993481E3809C6005B5E4D /* JSPerformanceObserver.h in Headers */,
+                               A5A9934A1E3809CB005B5E4D /* JSPerformanceObserverCallback.h in Headers */,
+                               A5A9934C1E3809CF005B5E4D /* JSPerformanceObserverEntryList.h in Headers */,
                                CB38FD5B1CD2325B00592A3F /* JSPerformanceResourceTiming.h in Headers */,
                                8A9A588811E84F37008ACFD1 /* JSPerformanceTiming.h in Headers */,
                                FDEA6247152102FC00479DF0 /* JSPeriodicWave.h in Headers */,
                                E5BA7D63151437CA00FE1E3F /* LengthFunctions.h in Headers */,
                                0F8716701C869D83004FF0DE /* LengthPoint.h in Headers */,
                                BCFF64920EAD15C200C1D6F7 /* LengthSize.h in Headers */,
+                               415747471E3869A400E914D8 /* LibWebRTCMacros.h in Headers */,
+                               417612B01E3A994000C3D81D /* LibWebRTCMediaEndpoint.h in Headers */,
+                               417612B21E3A994000C3D81D /* LibWebRTCPeerConnectionBackend.h in Headers */,
+                               415747481E3869A700E914D8 /* LibWebRTCProvider.h in Headers */,
+                               4157474A1E3869AD00E914D8 /* LibWebRTCUtils.h in Headers */,
                                84730D911248F0B300D3A9C9 /* LightSource.h in Headers */,
                                B22279650D00BF220071B782 /* LinearGradientAttributes.h in Headers */,
                                AB31C91E10AE1B8E000C7B92 /* LineClampValue.h in Headers */,
                                AD5A0C251DECACCC00707054 /* PerformanceLogging.h in Headers */,
                                83FE90271E307C30003E9199 /* PerformanceMonitor.h in Headers */,
                                8AF4E55611DC5A36000ED3DE /* PerformanceNavigation.h in Headers */,
+                               A5A9933D1E37FB19005B5E4D /* PerformanceObserver.h in Headers */,
+                               A5A9933F1E37FB1F005B5E4D /* PerformanceObserverCallback.h in Headers */,
+                               A5A993411E37FB28005B5E4D /* PerformanceObserverEntryList.h in Headers */,
                                86512EDF154A2AEF00A90426 /* PerformanceResourceTiming.h in Headers */,
                                8AF4E55C11DC5A63000ED3DE /* PerformanceTiming.h in Headers */,
                                A554B5F31E38393A001D4E03 /* PerformanceUserTiming.h in Headers */,
                                416E6FE91BBD12E5000A6043 /* ReadableStreamBuiltins.h in Headers */,
                                416E6FE81BBD12DF000A3F64 /* ReadableStreamInternalsBuiltins.h in Headers */,
                                FD31603C12B0267600C1A359 /* RealtimeAnalyser.h in Headers */,
+                               41103AAD1E39791000769F03 /* RealtimeIncomingAudioSource.h in Headers */,
                                4A4F65711AA997F100E38CDD /* RealtimeMediaSource.h in Headers */,
                                4A4F65721AA997F100E38CDD /* RealtimeMediaSourceCapabilities.h in Headers */,
                                4A0FFAA21AAF5EA20062803B /* RealtimeMediaSourceCenter.h in Headers */,
                                4A0FFAA61AAF5EF60062803B /* RealtimeMediaSourceCenterMac.h in Headers */,
                                4A4F65741AA997F100E38CDD /* RealtimeMediaSourceSettings.h in Headers */,
                                07C1C0E51BFB60ED00BD2256 /* RealtimeMediaSourceSupportedConstraints.h in Headers */,
+                               41103AAC1E39791000769F03 /* RealtimeOutgoingAudioSource.h in Headers */,
                                BC4368E80C226E32005EFB5F /* Rect.h in Headers */,
                                FD45A958175D414C00C21EC8 /* RectangleShape.h in Headers */,
                                9831AE4A154225C900FE2644 /* ReferrerPolicy.h in Headers */,
                                4998AEC613F9D0EA0090B1AA /* RequestAnimationFrameCallback.h in Headers */,
                                F55B3DD01251F12D003EF269 /* ResetInputType.h in Headers */,
                                7EE6846A12D26E3800E79415 /* ResourceError.h in Headers */,
-                               415747481E3869A700E914D8 /* LibWebRTCProvider.h in Headers */,
                                934F713C0D5A6F1900018D69 /* ResourceErrorBase.h in Headers */,
                                514C76790CE923A1007EF3CD /* ResourceHandle.h in Headers */,
                                26FAE4CD1852E3A5004C8C46 /* ResourceHandleCFURLConnectionDelegate.h in Headers */,
                                93B70D7009EB0C7C009D8468 /* ScriptController.h in Headers */,
                                4998AED213FB224D0090B1AA /* ScriptedAnimationController.h in Headers */,
                                08A484780E5272C500C3FE76 /* ScriptElement.h in Headers */,
+                               E3E4E2A81E3B17100023BB8A /* ScriptElementCachedScriptFetcher.h in Headers */,
                                E11C9D9B0EB3681200E409DB /* ScriptExecutionContext.h in Headers */,
                                41F066E40F64BCF600A07EAC /* ScriptGlobalObject.h in Headers */,
                                E38838991BAD145F00D62EE3 /* ScriptModuleLoader.h in Headers */,
                                414B82051D6DF0E50077EBE3 /* StructuredClone.h in Headers */,
                                BC5EB6A30E81DC4F00B25965 /* StyleBackgroundData.h in Headers */,
                                BC5EB67B0E81D3BE00B25965 /* StyleBoxData.h in Headers */,
-                               F48223111E3869B80066FC79 /* WebItemProviderPasteboard.h in Headers */,
                                8386A96D19F61B2E00E1EC4A /* StyleBuilder.h in Headers */,
                                83B9687B19F8AB83004EF7AF /* StyleBuilderConverter.h in Headers */,
                                835D363719FF6193004C93AB /* StyleBuilderCustom.h in Headers */,
                                A8EA800C0A19516E00A8EF5F /* StyleSheet.h in Headers */,
                                E4F9EEF3156DA00700D23E7E /* StyleSheetContents.h in Headers */,
                                A8EA800A0A19516E00A8EF5F /* StyleSheetList.h in Headers */,
-                               417612B21E3A994000C3D81D /* LibWebRTCPeerConnectionBackend.h in Headers */,
                                BC5EB5E50E81BF6D00B25965 /* StyleSurroundData.h in Headers */,
                                BC5EB8100E81F2CE00B25965 /* StyleTransformData.h in Headers */,
                                E4DEAA1817A93DC3000E0430 /* StyleTreeResolver.h in Headers */,
                                B22279AE0D00BF220071B782 /* SVGDefsElement.h in Headers */,
                                B22279B10D00BF220071B782 /* SVGDescElement.h in Headers */,
                                B22279B40D00BF220071B782 /* SVGDocument.h in Headers */,
-                               41103AAC1E39791000769F03 /* RealtimeOutgoingAudioSource.h in Headers */,
                                B28C6A280D00C44800334AA4 /* SVGDocumentExtensions.h in Headers */,
                                B22279B70D00BF220071B782 /* SVGElement.h in Headers */,
                                656581FE09D1508D000E61D7 /* SVGElementFactory.h in Headers */,
                                77A17A7812F28642004E02F6 /* WebGLVertexArrayObjectOES.h in Headers */,
                                A5840E25187B8AC200843B10 /* WebInjectedScriptHost.h in Headers */,
                                A584FE301864CB8400843B10 /* WebInjectedScriptManager.h in Headers */,
+                               F48223111E3869B80066FC79 /* WebItemProviderPasteboard.h in Headers */,
                                31C0FF220E4CEB6E007D6FE5 /* WebKitAnimationEvent.h in Headers */,
                                5DFEBAB718592B6D00C75BEB /* WebKitAvailability.h in Headers */,
                                498391590F1E776900C23782 /* WebKitCSSMatrix.h in Headers */,
                                51714EB01CF665CE004723C4 /* JSGCObservation.cpp in Sources */,
                                417DA71D13735DFA007C57FB /* JSInternals.cpp in Sources */,
                                A740B5A714C935AF00A77FA4 /* JSInternalSettings.cpp in Sources */,
-                               4157EBFA1E3AB67900AC9FE9 /* MockLibWebRTCPeerConnection.cpp in Sources */,
                                53ED3FDE167A88E7006762E6 /* JSInternalSettingsGenerated.cpp in Sources */,
                                A740B59714C935AF00A77FA4 /* JSMallocStatistics.cpp in Sources */,
                                CDF4B7331E03D14900E235A2 /* JSMediaKeysRequirement.cpp in Sources */,
                                A1B5B29E1AAA846E008B6042 /* MockContentFilterSettings.cpp in Sources */,
                                51058ADB1D6792C1009A538C /* MockGamepad.cpp in Sources */,
                                51058ADD1D6792C1009A538C /* MockGamepadProvider.cpp in Sources */,
+                               4157EBFA1E3AB67900AC9FE9 /* MockLibWebRTCPeerConnection.cpp in Sources */,
                                2D6F3E901C1ECB270061DBD4 /* MockPageOverlay.cpp in Sources */,
                                2D97F04719DD413C001EE9C3 /* MockPageOverlayClient.cpp in Sources */,
                                A140618B1E2ECA0A0032B34E /* MockQuickLookHandleClient.cpp in Sources */,
                                E1B4CD2510B322E200BFFD7E /* CredentialStorageMac.mm in Sources */,
                                2D481F00146B5C4C00AA7834 /* CrossfadeGeneratedImage.cpp in Sources */,
                                E1C416170F6563180092D2FB /* CrossOriginAccessControl.cpp in Sources */,
-                               417612B11E3A994000C3D81D /* LibWebRTCPeerConnectionBackend.cpp in Sources */,
                                41ABE67C1D0580E0006D862D /* CrossOriginPreflightChecker.cpp in Sources */,
                                E1C415DE0F655D7C0092D2FB /* CrossOriginPreflightResultCache.cpp in Sources */,
                                E16980491133644700894115 /* CRuntimeObject.cpp in Sources */,
                                9418278E1D8CAF9200492764 /* CSSPendingSubstitutionValue.cpp in Sources */,
                                977B3862122883E900B81FF8 /* CSSPreloadScanner.cpp in Sources */,
                                A80E6D050A1989CA007FB8C5 /* CSSPrimitiveValue.cpp in Sources */,
-                               F48223101E3869B80066FC79 /* WebItemProviderPasteboard.mm in Sources */,
                                A80E6CF70A1989CA007FB8C5 /* CSSProperty.cpp in Sources */,
                                78D02BC5154A18DF00B62D05 /* CSSPropertyAnimation.cpp in Sources */,
                                1ABA76CA11D20E50004C201C /* CSSPropertyNames.cpp in Sources */,
                                15FCC9FC1B4DF7F200E72326 /* DOMURLMediaStream.cpp in Sources */,
                                1403B99809EB13AF00797C7F /* DOMWindow.cpp in Sources */,
                                517FBA1E151AB17C00B57959 /* DOMWindowExtension.cpp in Sources */,
-                               41103AAE1E39791000769F03 /* RealtimeIncomingAudioSource.cpp in Sources */,
                                418C39561C8DAC7F0051C8A3 /* DOMWindowFetch.cpp in Sources */,
                                5185FC741BB4C4E80012898F /* DOMWindowIndexedDatabase.cpp in Sources */,
                                97B38E28151C4273004622E9 /* DOMWindowNotifications.cpp in Sources */,
                                A58C59D01E382EAC0047859C /* JSPerformanceMark.cpp in Sources */,
                                A58C59D21E382EB00047859C /* JSPerformanceMeasure.cpp in Sources */,
                                8A9A587011E84C36008ACFD1 /* JSPerformanceNavigation.cpp in Sources */,
+                               A5A9934D1E3809D7005B5E4D /* JSPerformanceObserver.cpp in Sources */,
+                               A5A993491E3809C9005B5E4D /* JSPerformanceObserverCallback.cpp in Sources */,
+                               A5A9934B1E3809CD005B5E4D /* JSPerformanceObserverEntryList.cpp in Sources */,
                                CB38FD5A1CD2325800592A3F /* JSPerformanceResourceTiming.cpp in Sources */,
                                0F43C85F189E15A600019AE2 /* JSPerformanceTiming.cpp in Sources */,
                                FDEA6246152102FC00479DF0 /* JSPeriodicWave.cpp in Sources */,
                                B2FA3DBA0AB75A6F000E5AC4 /* JSSVGPathSegArcRel.cpp in Sources */,
                                B2FA3DBC0AB75A6F000E5AC4 /* JSSVGPathSegClosePath.cpp in Sources */,
                                B2FA3DBE0AB75A6F000E5AC4 /* JSSVGPathSegCurvetoCubicAbs.cpp in Sources */,
-                               417612AF1E3A994000C3D81D /* LibWebRTCMediaEndpoint.cpp in Sources */,
                                B2FA3DC00AB75A6F000E5AC4 /* JSSVGPathSegCurvetoCubicRel.cpp in Sources */,
                                B2FA3DC20AB75A6F000E5AC4 /* JSSVGPathSegCurvetoCubicSmoothAbs.cpp in Sources */,
                                B2FA3DC40AB75A6F000E5AC4 /* JSSVGPathSegCurvetoCubicSmoothRel.cpp in Sources */,
                                E55F497A151B888000BB67DB /* LengthFunctions.cpp in Sources */,
                                0F87166F1C869D83004FF0DE /* LengthPoint.cpp in Sources */,
                                0FEF20CE1BD4A24100128E5D /* LengthSize.cpp in Sources */,
+                               417612AF1E3A994000C3D81D /* LibWebRTCMediaEndpoint.cpp in Sources */,
+                               417612B11E3A994000C3D81D /* LibWebRTCPeerConnectionBackend.cpp in Sources */,
+                               415747491E3869AA00E914D8 /* LibWebRTCUtils.cpp in Sources */,
                                FFB698CC1833EE0D00158A31 /* LineBreaker.cpp in Sources */,
                                89B5EAA111E8003D00F2367E /* LineEnding.cpp in Sources */,
                                FFB698CF183402BB00158A31 /* LineInfo.cpp in Sources */,
                                AD5A0C231DECACC000707054 /* PerformanceLoggingCocoa.mm in Sources */,
                                83FE90281E307C33003E9199 /* PerformanceMonitor.cpp in Sources */,
                                8AF4E55511DC5A36000ED3DE /* PerformanceNavigation.cpp in Sources */,
+                               A5A9933E1E37FB1C005B5E4D /* PerformanceObserver.cpp in Sources */,
+                               A5A993401E37FB25005B5E4D /* PerformanceObserverEntryList.cpp in Sources */,
                                86512EDE154A2AEF00A90426 /* PerformanceResourceTiming.cpp in Sources */,
                                0F43C85D189E10CF00019AE2 /* PerformanceTiming.cpp in Sources */,
                                A554B5F21E383938001D4E03 /* PerformanceUserTiming.cpp in Sources */,
                                6E84E9E017668BEE00815B68 /* RasterShape.cpp in Sources */,
                                418C39611C8F0AB10051C8A3 /* ReadableStreamDefaultController.cpp in Sources */,
                                FD31603B12B0267600C1A359 /* RealtimeAnalyser.cpp in Sources */,
+                               41103AAE1E39791000769F03 /* RealtimeIncomingAudioSource.cpp in Sources */,
                                4A4F65701AA997F100E38CDD /* RealtimeMediaSource.cpp in Sources */,
                                4A0FFAA11AAF5EA20062803B /* RealtimeMediaSourceCenter.cpp in Sources */,
                                4A0FFAA51AAF5EF60062803B /* RealtimeMediaSourceCenterMac.cpp in Sources */,
                                4A4F65731AA997F100E38CDD /* RealtimeMediaSourceSettings.cpp in Sources */,
                                2EC41DE41C0410A300D294FE /* RealtimeMediaSourceSupportedConstraints.cpp in Sources */,
+                               41103AAB1E39791000769F03 /* RealtimeOutgoingAudioSource.cpp in Sources */,
                                FD45A95A175D417100C21EC8 /* RectangleShape.cpp in Sources */,
                                BCAB418113E356E800D8AAF3 /* Region.cpp in Sources */,
                                CDFC360518CA61C20026E56F /* RemoteCommandListener.cpp in Sources */,
                                A83E1C740E49042C00140B9C /* ScriptControllerMac.mm in Sources */,
                                4998AED113FB224D0090B1AA /* ScriptedAnimationController.cpp in Sources */,
                                08A484770E5272C500C3FE76 /* ScriptElement.cpp in Sources */,
+                               E3E4E2A71E3B17100023BB8A /* ScriptElementCachedScriptFetcher.cpp in Sources */,
                                E11C9DB00EB3699500E409DB /* ScriptExecutionContext.cpp in Sources */,
                                41F066E50F64BCF600A07EAC /* ScriptGlobalObject.cpp in Sources */,
                                E38838981BAD145F00D62EE3 /* ScriptModuleLoader.cpp in Sources */,
                                512DD8E30D91E2B4000F89EE /* SharedBufferCF.cpp in Sources */,
                                97B1F02E13B025CA00F5103F /* SharedBufferChunkReader.cpp in Sources */,
                                1A4A95520B4EDCFF002D8C3C /* SharedBufferCocoa.mm in Sources */,
-                               415747491E3869AA00E914D8 /* LibWebRTCUtils.cpp in Sources */,
                                163E88F7118A39D200ED9231 /* SimpleFontDataCoreText.cpp in Sources */,
                                E48944A2180B57D800F165D8 /* SimpleLineLayout.cpp in Sources */,
                                585D6E031A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.cpp in Sources */,
                                93309E1B099E64920056E581 /* TextIterator.cpp in Sources */,
                                E4D988B617BFEB210084FB88 /* TextNodeTraversal.cpp in Sources */,
                                1C18DA58181AF6A500C4EF22 /* TextPainter.cpp in Sources */,
-                               41103AAB1E39791000769F03 /* RealtimeOutgoingAudioSource.cpp in Sources */,
                                E4C91A101802343900A17F6D /* TextPaintStyle.cpp in Sources */,
                                93F19A9D08245E59001E9ABC /* TextResourceDecoder.cpp in Sources */,
                                376DCCE113B4F966002EBEFC /* TextRun.cpp in Sources */,
                                29A8124A0FBB9CA900510293 /* WebAccessibilityObjectWrapperBase.mm in Sources */,
                                AAA728F816D1D8BC00D3BBC6 /* WebAccessibilityObjectWrapperIOS.mm in Sources */,
                                AA478A8016CD70C3007D1BB4 /* WebAccessibilityObjectWrapperMac.mm in Sources */,
-                               E3E4E2A71E3B17100023BB8A /* ScriptElementCachedScriptFetcher.cpp in Sources */,
                                2D3EF4491917915C00034184 /* WebActionDisablingCALayerDelegate.mm in Sources */,
                                120DE3ED1C86CA3E00B6D4DD /* WebAnimation.cpp in Sources */,
                                07D637411BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.mm in Sources */,
                                77A17A7712F28642004E02F6 /* WebGLVertexArrayObjectOES.cpp in Sources */,
                                A5840E24187B8AC200843B10 /* WebInjectedScriptHost.cpp in Sources */,
                                A584FE2F1864CB8400843B10 /* WebInjectedScriptManager.cpp in Sources */,
+                               F48223101E3869B80066FC79 /* WebItemProviderPasteboard.mm in Sources */,
                                31C0FF210E4CEB6E007D6FE5 /* WebKitAnimationEvent.cpp in Sources */,
                                498391580F1E776900C23782 /* WebKitCSSMatrix.cpp in Sources */,
                                8AA61CFF144D595B00F37350 /* WebKitCSSRegionRule.cpp in Sources */,
index 0456566..db83974 100644 (file)
 #if ENABLE(MEDIA_SOURCE)
 #include "DOMWindow.h"
 #include "MediaSource.h"
-#include "Performance.h"
 #include "VideoPlaybackQuality.h"
 #endif
 
index 68ee79e..5ae08fd 100644 (file)
@@ -57,7 +57,6 @@
 #include "MainFrame.h"
 #include "MemoryCache.h"
 #include "Page.h"
-#include "Performance.h"
 #include "PingLoader.h"
 #include "PlatformStrategies.h"
 #include "RenderElement.h"
index beb05ef..13d58f3 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "IntersectionObserverCallback.h"
 #include "IntersectionObserverEntry.h"
-#include <wtf/Optional.h>
 #include <wtf/RefCounted.h>
 #include <wtf/Variant.h>
 #include <wtf/text/WTFString.h>
index 2e59daa..3283c9a 100644 (file)
@@ -41,6 +41,7 @@
 #include "Frame.h"
 #include "PerformanceEntry.h"
 #include "PerformanceNavigation.h"
+#include "PerformanceObserver.h"
 #include "PerformanceResourceTiming.h"
 #include "PerformanceTiming.h"
 #include "PerformanceUserTiming.h"
@@ -171,7 +172,14 @@ ExceptionOr<void> Performance::mark(const String& markName)
 {
     if (!m_userTiming)
         m_userTiming = std::make_unique<UserTiming>(*this);
-    return m_userTiming->mark(markName);
+
+    auto result = m_userTiming->mark(markName);
+    if (result.hasException())
+        return result.releaseException();
+
+    queueEntry(result.releaseReturnValue());
+
+    return { };
 }
 
 void Performance::clearMarks(const String& markName)
@@ -185,7 +193,14 @@ ExceptionOr<void> Performance::measure(const String& measureName, const String&
 {
     if (!m_userTiming)
         m_userTiming = std::make_unique<UserTiming>(*this);
-    return m_userTiming->measure(measureName, startMark, endMark);
+
+    auto result = m_userTiming->measure(measureName, startMark, endMark);
+    if (result.hasException())
+        return result.releaseException();
+
+    queueEntry(result.releaseReturnValue());
+
+    return { };
 }
 
 void Performance::clearMeasures(const String& measureName)
@@ -195,6 +210,16 @@ void Performance::clearMeasures(const String& measureName)
     m_userTiming->clearMeasures(measureName);
 }
 
+void Performance::registerPerformanceObserver(PerformanceObserver& observer)
+{
+    m_observers.add(&observer);
+}
+
+void Performance::unregisterPerformanceObserver(PerformanceObserver& observer)
+{
+    m_observers.remove(&observer);
+}
+
 double Performance::now() const
 {
     double nowSeconds = monotonicallyIncreasingTime() - m_referenceTime;
@@ -207,6 +232,30 @@ double Performance::reduceTimeResolution(double seconds)
     return std::floor(seconds / resolutionSeconds) * resolutionSeconds;
 }
 
+void Performance::queueEntry(PerformanceEntry& entry)
+{
+    bool shouldScheduleTask = false;
+    for (auto& observer : m_observers) {
+        if (observer->typeFilter().contains(entry.type())) {
+            observer->queueEntry(entry);
+            shouldScheduleTask = true;
+        }
+    }
+
+    if (!shouldScheduleTask)
+        return;
+
+    if (m_performanceTimelineTaskQueue.hasPendingTasks())
+        return;
+
+    m_performanceTimelineTaskQueue.enqueueTask([this] () {
+        Vector<RefPtr<PerformanceObserver>> observers;
+        copyToVector(m_observers, observers);
+        for (auto& observer : observers)
+            observer->deliver();
+    });
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEB_TIMING)
index 0feebcc..f7414fc 100644 (file)
@@ -37,6 +37,8 @@
 #include "DOMWindowProperty.h"
 #include "EventTarget.h"
 #include "ExceptionOr.h"
+#include "GenericTaskQueue.h"
+#include <wtf/ListHashSet.h>
 
 namespace WebCore {
 
@@ -44,6 +46,7 @@ class Document;
 class LoadTiming;
 class PerformanceEntry;
 class PerformanceNavigation;
+class PerformanceObserver;
 class PerformanceTiming;
 class ResourceResponse;
 class URL;
@@ -67,17 +70,20 @@ public:
 
     void addResourceTiming(const String& initiatorName, Document*, const URL& originalURL, const ResourceResponse&, const LoadTiming&);
 
-    using RefCounted::ref;
-    using RefCounted::deref;
-
     ExceptionOr<void> mark(const String& markName);
     void clearMarks(const String& markName);
 
     ExceptionOr<void> measure(const String& measureName, const String& startMark, const String& endMark);
     void clearMeasures(const String& measureName);
 
+    void registerPerformanceObserver(PerformanceObserver&);
+    void unregisterPerformanceObserver(PerformanceObserver&);
+
     static double reduceTimeResolution(double seconds);
 
+    using RefCounted::ref;
+    using RefCounted::deref;
+
 private:
     explicit Performance(Frame&);
 
@@ -89,6 +95,8 @@ private:
 
     bool isResourceTimingBufferFull() const;
 
+    void queueEntry(PerformanceEntry&);
+
     mutable RefPtr<PerformanceNavigation> m_navigation;
     mutable RefPtr<PerformanceTiming> m_timing;
 
@@ -99,6 +107,9 @@ private:
     double m_referenceTime;
 
     std::unique_ptr<UserTiming> m_userTiming;
+
+    GenericTaskQueue<Timer> m_performanceTimelineTaskQueue;
+    ListHashSet<RefPtr<PerformanceObserver>> m_observers;
 };
 
 }
index 0a6c5e9..a85fbdb 100644 (file)
 
 #if ENABLE(WEB_TIMING)
 
+#include "RuntimeEnabledFeatures.h"
+
 namespace WebCore {
 
-PerformanceEntry::PerformanceEntry(const String& name, const String& entryType, double startTime, double finishTime)
+PerformanceEntry::PerformanceEntry(Type type, const String& name, const String& entryType, double startTime, double finishTime)
     : m_name(name)
     , m_entryType(entryType)
     , m_startTime(startTime)
     , m_duration(finishTime - startTime)
+    , m_type(type)
 {
 }
 
@@ -47,6 +50,26 @@ PerformanceEntry::~PerformanceEntry()
 {
 }
 
+std::optional<PerformanceEntry::Type> PerformanceEntry::parseEntryTypeString(const String& entryType)
+{
+    if (entryType == "navigation")
+        return std::optional<Type>(Type::Navigation);
+
+    if (RuntimeEnabledFeatures::sharedFeatures().userTimingEnabled()) {
+        if (entryType == "mark")
+            return std::optional<Type>(Type::Mark);
+        if (entryType == "measure")
+            return std::optional<Type>(Type::Measure);
+    }
+
+    if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled()) {
+        if (entryType == "resource")
+            return std::optional<Type>(Type::Resource);
+    }
+
+    return std::nullopt;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEB_TIMING)
index 68c1019..7ebee6a 100644 (file)
@@ -34,6 +34,7 @@
 #if ENABLE(WEB_TIMING)
 
 #include "Performance.h"
+#include <wtf/Optional.h>
 #include <wtf/RefCounted.h>
 #include <wtf/TypeCasts.h>
 #include <wtf/text/WTFString.h>
@@ -49,6 +50,17 @@ public:
     double startTime() const { return m_startTime; }
     double duration() const { return m_duration; }
 
+    enum class Type {
+        Navigation = 1 << 0,
+        Mark = 1 << 1,
+        Measure = 1 << 2,
+        Resource = 1 << 3,
+    };
+
+    Type type() const { return m_type; }
+
+    static std::optional<Type> parseEntryTypeString(const String& entryType);
+
     virtual bool isResource() const { return false; }
     virtual bool isMark() const { return false; }
     virtual bool isMeasure() const { return false; }
@@ -59,13 +71,14 @@ public:
     }
 
 protected:
-    PerformanceEntry(const String& name, const String& entryType, double startTime, double finishTime);
+    PerformanceEntry(Type, const String& name, const String& entryType, double startTime, double finishTime);
 
 private:
     const String m_name;
     const String m_entryType;
     const double m_startTime;
     const double m_duration;
+    const Type m_type;
 };
 
 } // namespace WebCore
index 4fa9ace..528ba19 100644 (file)
@@ -39,7 +39,11 @@ public:
     bool isMark() const override { return true; }
     
 private:
-    PerformanceMark(const String& name, double startTime) : PerformanceEntry(name, ASCIILiteral("mark"), startTime, startTime) { }
+    PerformanceMark(const String& name, double startTime)
+        : PerformanceEntry(PerformanceEntry::Type::Mark, name, ASCIILiteral("mark"), startTime, startTime)
+    {
+    }
+
     ~PerformanceMark() { }
 };
 
index f120d90..cdb0b6c 100644 (file)
@@ -39,7 +39,11 @@ public:
     bool isMeasure() const override { return true; }
 
 private:
-    PerformanceMeasure(const String& name, double startTime, double duration) : PerformanceEntry(name, ASCIILiteral("measure"), startTime, duration) { }
+    PerformanceMeasure(const String& name, double startTime, double duration)
+        : PerformanceEntry(PerformanceEntry::Type::Measure, name, ASCIILiteral("measure"), startTime, duration)
+    {
+    }
+
     ~PerformanceMeasure() { }
 };
 
diff --git a/Source/WebCore/page/PerformanceObserver.cpp b/Source/WebCore/page/PerformanceObserver.cpp
new file mode 100644 (file)
index 0000000..44ae3f5
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PerformanceObserver.h"
+
+#if ENABLE(WEB_TIMING)
+
+#include "DOMWindow.h"
+#include "Document.h"
+#include "ExceptionCode.h"
+#include "Performance.h"
+#include "PerformanceObserverEntryList.h"
+#include "WorkerGlobalScope.h"
+
+namespace WebCore {
+
+PerformanceObserver::PerformanceObserver(ScriptExecutionContext& scriptExecutionContext, Ref<PerformanceObserverCallback>&& callback)
+    : m_callback(WTFMove(callback))
+{
+    if (is<Document>(scriptExecutionContext)) {
+        auto& document = downcast<Document>(scriptExecutionContext);
+        if (DOMWindow* window = document.domWindow())
+            m_performance = window->performance();
+    } else if (is<WorkerGlobalScope>(scriptExecutionContext)) {
+        // FIXME: Support Performance Timeline for Workers.
+    } else
+        ASSERT_NOT_REACHED();
+}
+
+ExceptionOr<void> PerformanceObserver::observe(Init&& init)
+{
+    if (!m_performance)
+        return Exception { TypeError };
+
+    if (init.entryTypes.isEmpty())
+        return Exception { TypeError, ASCIILiteral("entryTypes cannot be an empty list") };
+
+    OptionSet<PerformanceEntry::Type> filter;
+    for (const String& entryType : init.entryTypes) {
+        if (auto type = PerformanceEntry::parseEntryTypeString(entryType))
+            filter |= *type;
+    }
+
+    if (filter.isEmpty())
+        return Exception { TypeError, ASCIILiteral("entryTypes contained only unsupported types") };
+
+    m_typeFilter = filter;
+
+    if (!m_registered) {
+        m_performance->registerPerformanceObserver(*this);
+        m_registered = true;
+    }
+
+    return { };
+}
+
+void PerformanceObserver::disconnect()
+{
+    if (m_performance)
+        m_performance->unregisterPerformanceObserver(*this);
+
+    m_registered = false;
+    m_entriesToDeliver.clear();
+}
+
+void PerformanceObserver::queueEntry(PerformanceEntry& entry)
+{
+    m_entriesToDeliver.append(&entry);
+}
+
+void PerformanceObserver::deliver()
+{
+    if (m_entriesToDeliver.isEmpty())
+        return;
+
+    Vector<RefPtr<PerformanceEntry>> entries = WTFMove(m_entriesToDeliver);
+    auto list = PerformanceObserverEntryList::create(WTFMove(entries));
+    m_callback->handleEvent(list.ptr(), this);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/page/PerformanceObserver.h b/Source/WebCore/page/PerformanceObserver.h
new file mode 100644 (file)
index 0000000..f17fc73
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_TIMING)
+
+#include "ExceptionOr.h"
+#include "PerformanceEntry.h"
+#include "PerformanceObserverCallback.h"
+#include <wtf/OptionSet.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Performance;
+class ScriptExecutionContext;
+
+class PerformanceObserver : public RefCounted<PerformanceObserver> {
+public:
+    struct Init {
+        Vector<String> entryTypes;
+    };
+
+    static Ref<PerformanceObserver> create(ScriptExecutionContext& context, Ref<PerformanceObserverCallback>&& callback)
+    {
+        return adoptRef(*new PerformanceObserver(context, WTFMove(callback)));
+    }
+
+    ExceptionOr<void> observe(Init&&);
+    void disconnect();
+
+    OptionSet<PerformanceEntry::Type> typeFilter() const { return m_typeFilter; }
+
+    void queueEntry(PerformanceEntry&);
+    void deliver();
+
+private:
+    PerformanceObserver(ScriptExecutionContext&, Ref<PerformanceObserverCallback>&&);
+
+    RefPtr<Performance> m_performance;
+    Vector<RefPtr<PerformanceEntry>> m_entriesToDeliver;
+    Ref<PerformanceObserverCallback> m_callback;
+    OptionSet<PerformanceEntry::Type> m_typeFilter;
+    bool m_registered { false };
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/page/PerformanceObserver.idl b/Source/WebCore/page/PerformanceObserver.idl
new file mode 100644 (file)
index 0000000..588334e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// https://w3c.github.io/performance-timeline/
+
+[
+    Conditional=WEB_TIMING,
+    Constructor(PerformanceObserverCallback callback),
+    ConstructorCallWith=ScriptExecutionContext,
+    EnabledAtRuntime=PerformanceTimeline,
+    ImplementationLacksVTable,
+] interface PerformanceObserver {
+    [MayThrowException] void observe(PerformanceObserverInit options);
+    void disconnect();
+};
+
+[
+    Conditional=WEB_TIMING,
+]
+dictionary PerformanceObserverInit {
+    required sequence<DOMString> entryTypes;
+};
diff --git a/Source/WebCore/page/PerformanceObserverCallback.h b/Source/WebCore/page/PerformanceObserverCallback.h
new file mode 100644 (file)
index 0000000..9135c39
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_TIMING)
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class PerformanceObserver;
+class PerformanceObserverEntryList;
+
+class PerformanceObserverCallback : public RefCounted<PerformanceObserverCallback> {
+public:
+    virtual ~PerformanceObserverCallback() { }
+    virtual bool handleEvent(PerformanceObserverEntryList*, PerformanceObserver*) = 0;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/page/PerformanceObserverCallback.idl b/Source/WebCore/page/PerformanceObserverCallback.idl
new file mode 100644 (file)
index 0000000..cc9a1dc
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// https://w3c.github.io/performance-timeline/
+
+[
+    Conditional=WEB_TIMING,
+] callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
diff --git a/Source/WebCore/page/PerformanceObserverEntryList.cpp b/Source/WebCore/page/PerformanceObserverEntryList.cpp
new file mode 100644 (file)
index 0000000..7d09ef0
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PerformanceObserverEntryList.h"
+
+#if ENABLE(WEB_TIMING)
+
+#include "PerformanceEntry.h"
+
+namespace WebCore {
+
+Ref<PerformanceObserverEntryList> PerformanceObserverEntryList::create(Vector<RefPtr<PerformanceEntry>>&& entries)
+{
+    return adoptRef(*new PerformanceObserverEntryList(WTFMove(entries)));
+}
+
+PerformanceObserverEntryList::PerformanceObserverEntryList(Vector<RefPtr<PerformanceEntry>>&& entries)
+    : m_entries(WTFMove(entries))
+{
+    ASSERT(!m_entries.isEmpty());
+
+    std::stable_sort(m_entries.begin(), m_entries.end(), PerformanceEntry::startTimeCompareLessThan);
+}
+
+Vector<RefPtr<PerformanceEntry>> PerformanceObserverEntryList::getEntriesByType(const String& entryType) const
+{
+    return getEntriesByName(String(), entryType);
+}
+
+Vector<RefPtr<PerformanceEntry>> PerformanceObserverEntryList::getEntriesByName(const String& name, const String& entryType) const
+{
+    Vector<RefPtr<PerformanceEntry>> entries;
+
+    // PerformanceObservers can only be registered for valid types.
+    // So if the incoming entryType is an unknown type, there will be no matches.
+    std::optional<PerformanceEntry::Type> type;
+    if (!entryType.isNull()) {
+        type = PerformanceEntry::parseEntryTypeString(entryType);
+        if (!type)
+            return entries;
+    }
+
+    for (auto& entry : m_entries) {
+        if (!name.isNull() && entry->name() != name)
+            continue;
+        if (type && entry->type() != *type)
+            continue;
+        entries.append(entry.copyRef());
+    }
+
+    return entries;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/page/PerformanceObserverEntryList.h b/Source/WebCore/page/PerformanceObserverEntryList.h
new file mode 100644 (file)
index 0000000..3af690c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_TIMING)
+
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class PerformanceEntry;
+
+class PerformanceObserverEntryList : public RefCounted<PerformanceObserverEntryList> {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static Ref<PerformanceObserverEntryList> create(Vector<RefPtr<PerformanceEntry>>&& entries);
+
+    const Vector<RefPtr<PerformanceEntry>>& getEntries() const { return m_entries; }
+    Vector<RefPtr<PerformanceEntry>> getEntriesByType(const String& entryType) const;
+    Vector<RefPtr<PerformanceEntry>> getEntriesByName(const String& name, const String& entryType) const;
+
+private:
+    PerformanceObserverEntryList(Vector<RefPtr<PerformanceEntry>>&& entries);
+
+    Vector<RefPtr<PerformanceEntry>> m_entries;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/page/PerformanceObserverEntryList.idl b/Source/WebCore/page/PerformanceObserverEntryList.idl
new file mode 100644 (file)
index 0000000..0ee7040
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// https://w3c.github.io/performance-timeline/
+
+[
+    Conditional=WEB_TIMING,
+    EnabledAtRuntime=PerformanceTimeline,
+    ImplementationLacksVTable,
+] interface PerformanceObserverEntryList {
+    PerformanceEntryList getEntries();
+    PerformanceEntryList getEntriesByType(DOMString type);
+    PerformanceEntryList getEntriesByName(DOMString name, optional DOMString type);
+};
+
+typedef sequence<PerformanceEntry> PerformanceEntryList;
index 0a3233b..6769e1d 100644 (file)
@@ -76,7 +76,7 @@ static bool passesTimingAllowCheck(const ResourceResponse& response, Document* r
 }
 
 PerformanceResourceTiming::PerformanceResourceTiming(const AtomicString& initiatorType, const URL& originalURL, const ResourceResponse& response, LoadTiming loadTiming, Document* requestingDocument)
-    : PerformanceEntry(originalURL.string(), ASCIILiteral("resource"), monotonicTimeToDocumentMilliseconds(requestingDocument, loadTiming.startTime()), monotonicTimeToDocumentMilliseconds(requestingDocument, loadTiming.responseEnd()))
+    : PerformanceEntry(PerformanceEntry::Type::Resource, originalURL.string(), ASCIILiteral("resource"), monotonicTimeToDocumentMilliseconds(requestingDocument, loadTiming.startTime()), monotonicTimeToDocumentMilliseconds(requestingDocument, loadTiming.responseEnd()))
     , m_initiatorType(initiatorType)
     , m_timing(response.networkLoadTiming())
     , m_loadTiming(loadTiming)
index abbe950..7b9400d 100644 (file)
@@ -30,9 +30,6 @@
 
 #include "ExceptionCode.h"
 #include "Performance.h"
-#include "PerformanceEntry.h"
-#include "PerformanceMark.h"
-#include "PerformanceMeasure.h"
 #include "PerformanceTiming.h"
 #include <array>
 #include <wtf/NeverDestroyed.h>
@@ -98,15 +95,15 @@ static void clearPerformanceEntries(PerformanceEntryMap& performanceEntryMap, co
     performanceEntryMap.remove(name);
 }
 
-ExceptionOr<void> UserTiming::mark(const String& markName)
+ExceptionOr<Ref<PerformanceMark>> UserTiming::mark(const String& markName)
 {
     if (restrictedMarkFunction(markName))
         return Exception { SYNTAX_ERR };
 
     auto& performanceEntryList = m_marksMap.ensure(markName, [] { return Vector<RefPtr<PerformanceEntry>>(); }).iterator->value;
-    performanceEntryList.append(PerformanceMark::create(markName, m_performance.now()));
-
-    return { };
+    auto entry = PerformanceMark::create(markName, m_performance.now());
+    performanceEntryList.append(entry.copyRef());
+    return WTFMove(entry);
 }
 
 void UserTiming::clearMarks(const String& markName)
@@ -129,7 +126,7 @@ ExceptionOr<double> UserTiming::findExistingMarkStartTime(const String& markName
     return Exception { SYNTAX_ERR };
 }
 
-ExceptionOr<void> UserTiming::measure(const String& measureName, const String& startMark, const String& endMark)
+ExceptionOr<Ref<PerformanceMeasure>> UserTiming::measure(const String& measureName, const String& startMark, const String& endMark)
 {
     double startTime = 0.0;
     double endTime = 0.0;
@@ -154,9 +151,9 @@ ExceptionOr<void> UserTiming::measure(const String& measureName, const String& s
     }
 
     auto& performanceEntryList = m_measuresMap.ensure(measureName, [] { return Vector<RefPtr<PerformanceEntry>>(); }).iterator->value;
-    performanceEntryList.append(PerformanceMeasure::create(measureName, startTime, endTime));
-
-    return { };
+    auto entry = PerformanceMeasure::create(measureName, startTime, endTime);
+    performanceEntryList.append(entry.copyRef());
+    return WTFMove(entry);
 }
 
 void UserTiming::clearMeasures(const String& measureName)
index 574e124..7831373 100644 (file)
 #if ENABLE(WEB_TIMING)
 
 #include "ExceptionOr.h"
+#include "PerformanceMark.h"
+#include "PerformanceMeasure.h"
 #include <wtf/HashMap.h>
 #include <wtf/text/StringHash.h>
 
 namespace WebCore {
 
 class Performance;
-class PerformanceEntry;
 
 using PerformanceEntryMap = HashMap<String, Vector<RefPtr<PerformanceEntry>>>;
 
@@ -42,10 +43,10 @@ class UserTiming {
 public:
     explicit UserTiming(Performance&);
 
-    ExceptionOr<void> mark(const String& markName);
+    ExceptionOr<Ref<PerformanceMark>> mark(const String& markName);
     void clearMarks(const String& markName);
 
-    ExceptionOr<void> measure(const String& measureName, const String& startMark, const String& endMark);
+    ExceptionOr<Ref<PerformanceMeasure>> measure(const String& measureName, const String& startMark, const String& endMark);
     void clearMeasures(const String& measureName);
 
     Vector<RefPtr<PerformanceEntry>> getMarks() const;
index b8c63a7..65c412d 100644 (file)
@@ -1,3 +1,14 @@
+2017-01-30  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Implement PerformanceObserver
+        https://bugs.webkit.org/show_bug.cgi?id=167546
+        <rdar://problem/30247959>
+
+        Reviewed by Ryosuke Niwa.
+
+        * UserInterface/Models/NativeFunctionParameters.js:
+        Improve API view display of built-in performance methods.
+
 2017-01-30  Matt Baker  <mattbaker@apple.com>
 
         Web Inspector: Need some limit on Async Call Stacks for async loops (rAF loops)
index 8ea724a..9ba50a2 100644 (file)
@@ -1231,6 +1231,27 @@ WebInspector.NativePrototypeFunctionParameters = {
         __proto__: null,
     },
 
+    Performance: {
+        clearMarks: "[name]",
+        clearMeasures: "name",
+        getEntriesByName: "name, [type]",
+        getEntriesByType: "type",
+        mark: "name",
+        measure: "name, [startMark], [endMark]",
+        __proto__: null,
+    },
+
+    PerformanceObserver: {
+        observe: "options",
+        __proto__: null,
+    },
+
+    PerformanceObserverEntryList: {
+        getEntriesByName: "name, [type]",
+        getEntriesByType: "type",
+        __proto__: null,
+    },
+
     Plugin: {
         item: "[index]",
         namedItem: "[name]",