Support Performance API (performance.now(), UserTiming) in Workers
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Feb 2017 22:07:28 +0000 (22:07 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Feb 2017 22:07:28 +0000 (22:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=167717

Reviewed by Ryosuke Niwa.

Source/WebCore:

Tests: performance-api/performance-mark-name.html
       performance-api/performance-now-api.html
       performance-api/performance-now-time-origin-in-worker.html
       performance-api/user-timing-apis.html

* CMakeLists.txt:
* DerivedSources.make:
New files.

* page/DOMWindow.idl:
* page/GlobalPerformance.idl:
* workers/WorkerGlobalScope.idl:
Add partial interface for performance attribute.

* page/Performance.idl:
* page/PerformanceEntry.idl:
* page/PerformanceMark.idl:
* page/PerformanceMeasure.idl:
* page/PerformanceObserver.idl:
* page/PerformanceObserverEntryList.idl:
Expose these to Workers.

* page/Performance.cpp:
(WebCore::Performance::Performance):
(WebCore::Performance::contextDestroyed):
* page/Performance.h:
Use the EventQueue variant that works with any ScriptExectionContext.

* page/PerformanceObserver.cpp:
(WebCore::PerformanceObserver::PerformanceObserver):
Get the Performance base in a Worker context.

* page/PerformanceUserTiming.cpp:
(WebCore::UserTiming::mark):
Only reject legacy special mark names in a Window, not a Worker.

(WebCore::UserTiming::findExistingMarkStartTime):
Simple implementation returns 0 as the start time in Workers. The spec
is currently imprecise here, but it does not have the unusual
PerformanceTiming behavior in a Window which is part of User Timing 1.

* workers/Worker.cpp:
(WebCore::Worker::create):
(WebCore::Worker::notifyFinished):
* workers/Worker.h:
Record the moment of Worker creation.

* workers/WorkerGlobalScope.cpp:
(WebCore::WorkerGlobalScope::WorkerGlobalScope):
(WebCore::WorkerGlobalScope::performance):
* workers/WorkerGlobalScope.h:
Construct the Performance object with the moment of creation (timeOrigin).

* workers/DedicatedWorkerGlobalScope.cpp:
(WebCore::DedicatedWorkerGlobalScope::create):
(WebCore::DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope):
* workers/DedicatedWorkerGlobalScope.h:
* workers/DedicatedWorkerThread.cpp:
(WebCore::DedicatedWorkerThread::DedicatedWorkerThread):
(WebCore::DedicatedWorkerThread::createWorkerGlobalScope):
* workers/DedicatedWorkerThread.h:
* workers/WorkerGlobalScopeProxy.h:
* workers/WorkerMessagingProxy.cpp:
(WebCore::WorkerMessagingProxy::startWorkerGlobalScope):
* workers/WorkerMessagingProxy.h:
* workers/WorkerThread.cpp:
(WebCore::WorkerThreadStartupData::WorkerThreadStartupData):
(WebCore::WorkerThread::WorkerThread):
(WebCore::WorkerThread::workerThread):
* workers/WorkerThread.h:
Pass the moment of creation (timeOrigin) through to WorkerGlobalScope creation.

LayoutTests:

* js/dom/global-constructors-attributes-dedicated-worker-expected.txt:
Updated now that Performance classes are in Workers.

* performance-api/performance-now-api-expected.txt: Added.
* performance-api/performance-now-api.html: Added.
* performance-api/performance-now-time-origin-in-worker-expected.txt: Added.
* performance-api/performance-now-time-origin-in-worker.html: Added.
New tests to cover performance.now.

* performance-api/performance-mark-name-expected.txt: Added.
* performance-api/performance-mark-name.html: Added.
* performance-api/resources/mark-name.js: Added.
* performance-api/resources/user-timing-api.js: Added.
* performance-api/user-timing-apis-expected.txt: Added.
* performance-api/user-timing-apis.html: Added.
New tests to cover user-timing and performance.mark behavior.

* performance-api/performance-observer-api-expected.txt:
* performance-api/performance-observer-api.html:
* performance-api/performance-observer-basic-expected.txt:
* performance-api/performance-observer-basic.html:
* performance-api/performance-timeline-api-expected.txt:
* performance-api/performance-timeline-api.html:
* performance-api/resources/now-api.js: Added.
* performance-api/resources/observer-api.js: Copied from LayoutTests/performance-api/performance-observer-api.html.
* performance-api/resources/observer-basic.js: Copied from LayoutTests/performance-api/performance-observer-basic.html.
* performance-api/resources/time-origin-in-worker.js: Added.
* performance-api/resources/timeline-api.js: Copied from LayoutTests/performance-api/performance-timeline-api.html.
Update some of the existing tests to check in a Document and Worker.

* imported/w3c/web-platform-tests/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes-expected.txt:
Minor progression.

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

53 files changed:
LayoutTests/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes-expected.txt
LayoutTests/js/dom/global-constructors-attributes-dedicated-worker-expected.txt
LayoutTests/performance-api/performance-mark-name-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-mark-name.html [new file with mode: 0644]
LayoutTests/performance-api/performance-now-api-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-now-api.html [new file with mode: 0644]
LayoutTests/performance-api/performance-now-time-origin-in-worker-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/performance-now-time-origin-in-worker.html [new file with mode: 0644]
LayoutTests/performance-api/performance-observer-api-expected.txt
LayoutTests/performance-api/performance-observer-api.html
LayoutTests/performance-api/performance-observer-basic-expected.txt
LayoutTests/performance-api/performance-observer-basic.html
LayoutTests/performance-api/performance-timeline-api-expected.txt
LayoutTests/performance-api/performance-timeline-api.html
LayoutTests/performance-api/resources/mark-name.js [new file with mode: 0644]
LayoutTests/performance-api/resources/now-api.js [new file with mode: 0644]
LayoutTests/performance-api/resources/observer-api.js [new file with mode: 0644]
LayoutTests/performance-api/resources/observer-basic.js [new file with mode: 0644]
LayoutTests/performance-api/resources/time-origin-in-worker.js [new file with mode: 0644]
LayoutTests/performance-api/resources/timeline-api.js [new file with mode: 0644]
LayoutTests/performance-api/resources/user-timing-api.js [new file with mode: 0644]
LayoutTests/performance-api/user-timing-apis-expected.txt [new file with mode: 0644]
LayoutTests/performance-api/user-timing-apis.html [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources.make
Source/WebCore/page/DOMWindow.idl
Source/WebCore/page/GlobalPerformance.idl [new file with mode: 0644]
Source/WebCore/page/Performance.cpp
Source/WebCore/page/Performance.h
Source/WebCore/page/Performance.idl
Source/WebCore/page/PerformanceEntry.idl
Source/WebCore/page/PerformanceMark.idl
Source/WebCore/page/PerformanceMeasure.idl
Source/WebCore/page/PerformanceObserver.cpp
Source/WebCore/page/PerformanceObserver.idl
Source/WebCore/page/PerformanceObserverEntryList.idl
Source/WebCore/page/PerformanceUserTiming.cpp
Source/WebCore/workers/DedicatedWorkerGlobalScope.cpp
Source/WebCore/workers/DedicatedWorkerGlobalScope.h
Source/WebCore/workers/DedicatedWorkerThread.cpp
Source/WebCore/workers/DedicatedWorkerThread.h
Source/WebCore/workers/Worker.cpp
Source/WebCore/workers/Worker.h
Source/WebCore/workers/WorkerGlobalScope.cpp
Source/WebCore/workers/WorkerGlobalScope.h
Source/WebCore/workers/WorkerGlobalScope.idl
Source/WebCore/workers/WorkerGlobalScopeProxy.h
Source/WebCore/workers/WorkerMessagingProxy.cpp
Source/WebCore/workers/WorkerMessagingProxy.h
Source/WebCore/workers/WorkerThread.cpp
Source/WebCore/workers/WorkerThread.h

index 6e4e064..b67fa0b 100644 (file)
@@ -1,3 +1,43 @@
+2017-02-02  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Support Performance API (performance.now(), UserTiming) in Workers
+        https://bugs.webkit.org/show_bug.cgi?id=167717
+
+        Reviewed by Ryosuke Niwa.
+
+        * js/dom/global-constructors-attributes-dedicated-worker-expected.txt:
+        Updated now that Performance classes are in Workers.
+
+        * performance-api/performance-now-api-expected.txt: Added.
+        * performance-api/performance-now-api.html: Added.
+        * performance-api/performance-now-time-origin-in-worker-expected.txt: Added.
+        * performance-api/performance-now-time-origin-in-worker.html: Added.
+        New tests to cover performance.now.
+
+        * performance-api/performance-mark-name-expected.txt: Added.
+        * performance-api/performance-mark-name.html: Added.
+        * performance-api/resources/mark-name.js: Added.
+        * performance-api/resources/user-timing-api.js: Added.
+        * performance-api/user-timing-apis-expected.txt: Added.
+        * performance-api/user-timing-apis.html: Added.
+        New tests to cover user-timing and performance.mark behavior.
+
+        * performance-api/performance-observer-api-expected.txt:
+        * performance-api/performance-observer-api.html:
+        * performance-api/performance-observer-basic-expected.txt:
+        * performance-api/performance-observer-basic.html:
+        * performance-api/performance-timeline-api-expected.txt:
+        * performance-api/performance-timeline-api.html:
+        * performance-api/resources/now-api.js: Added.
+        * performance-api/resources/observer-api.js: Copied from LayoutTests/performance-api/performance-observer-api.html.
+        * performance-api/resources/observer-basic.js: Copied from LayoutTests/performance-api/performance-observer-basic.html.
+        * performance-api/resources/time-origin-in-worker.js: Added.
+        * performance-api/resources/timeline-api.js: Copied from LayoutTests/performance-api/performance-timeline-api.html.
+        Update some of the existing tests to check in a Document and Worker.
+
+        * imported/w3c/web-platform-tests/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes-expected.txt:
+        Minor progression.
+
 2017-02-02  Ryan Haddad  <ryanhaddad@apple.com>
 
         Mark imported/w3c/web-platform-tests/shadow-dom/slotchange.html as flaky on macOS.
index a20274b..0038d08 100644 (file)
@@ -5,5 +5,5 @@ This test validates exception scenarios of invoking mark() and measure() with ti
 
 PASS window.performance is defined 
 FAIL performance.mark and performance.measure should throw if used with timing attribute values assert_throws: function "function () { window.performance.measure(timingAttributes..." did not throw
-FAIL performance.mark and performance.measure should not throw if used with timing attribute values in workers Can't find variable: performance
+PASS performance.mark and performance.measure should not throw if used with timing attribute values in workers 
 
index e1e740a..7c620d4 100644 (file)
@@ -194,6 +194,36 @@ PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Object').hasOwnProperty('
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Object').hasOwnProperty('set') is false
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Object').enumerable is false
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Object').configurable is true
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Performance').value is Performance
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Performance').hasOwnProperty('get') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Performance').hasOwnProperty('set') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Performance').enumerable is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Performance').configurable is true
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceEntry').value is PerformanceEntry
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceEntry').hasOwnProperty('get') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceEntry').hasOwnProperty('set') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceEntry').enumerable is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceEntry').configurable is true
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMark').value is PerformanceMark
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMark').hasOwnProperty('get') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMark').hasOwnProperty('set') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMark').enumerable is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMark').configurable is true
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMeasure').value is PerformanceMeasure
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMeasure').hasOwnProperty('get') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMeasure').hasOwnProperty('set') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMeasure').enumerable is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceMeasure').configurable is true
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').value is PerformanceObserver
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('get') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').hasOwnProperty('set') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').enumerable is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserver').configurable is true
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').value is PerformanceObserverEntryList
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('get') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').hasOwnProperty('set') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').enumerable is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'PerformanceObserverEntryList').configurable is true
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'ProgressEvent').value is ProgressEvent
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'ProgressEvent').hasOwnProperty('get') is false
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'ProgressEvent').hasOwnProperty('set') is false
diff --git a/LayoutTests/performance-api/performance-mark-name-expected.txt b/LayoutTests/performance-api/performance-mark-name-expected.txt
new file mode 100644 (file)
index 0000000..7540536
--- /dev/null
@@ -0,0 +1,55 @@
+Tests performance.mark name restrictions apply only in Window.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS performance.mark("navigationStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("unloadEventStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("unloadEventEnd") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("redirectStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("redirectEnd") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("fetchStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("domainLookupStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("domainLookupEnd") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("connectStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("connectEnd") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("secureConnectionStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("requestStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("responseStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("responseEnd") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("domLoading") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("domInteractive") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("domContentLoadedEventStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("domContentLoadedEventEnd") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("domComplete") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("loadEventStart") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("loadEventEnd") threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
+PASS performance.mark("mark_name") did not throw exception.
+
+Starting worker: resources/mark-name.js
+PASS [Worker] performance.mark("navigationStart") did not throw exception.
+PASS [Worker] performance.mark("unloadEventStart") did not throw exception.
+PASS [Worker] performance.mark("unloadEventEnd") did not throw exception.
+PASS [Worker] performance.mark("redirectStart") did not throw exception.
+PASS [Worker] performance.mark("redirectEnd") did not throw exception.
+PASS [Worker] performance.mark("fetchStart") did not throw exception.
+PASS [Worker] performance.mark("domainLookupStart") did not throw exception.
+PASS [Worker] performance.mark("domainLookupEnd") did not throw exception.
+PASS [Worker] performance.mark("connectStart") did not throw exception.
+PASS [Worker] performance.mark("connectEnd") did not throw exception.
+PASS [Worker] performance.mark("secureConnectionStart") did not throw exception.
+PASS [Worker] performance.mark("requestStart") did not throw exception.
+PASS [Worker] performance.mark("responseStart") did not throw exception.
+PASS [Worker] performance.mark("responseEnd") did not throw exception.
+PASS [Worker] performance.mark("domLoading") did not throw exception.
+PASS [Worker] performance.mark("domInteractive") did not throw exception.
+PASS [Worker] performance.mark("domContentLoadedEventStart") did not throw exception.
+PASS [Worker] performance.mark("domContentLoadedEventEnd") did not throw exception.
+PASS [Worker] performance.mark("domComplete") did not throw exception.
+PASS [Worker] performance.mark("loadEventStart") did not throw exception.
+PASS [Worker] performance.mark("loadEventEnd") did not throw exception.
+PASS [Worker] performance.mark("mark_name") did not throw exception.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-mark-name.html b/LayoutTests/performance-api/performance-mark-name.html
new file mode 100644 (file)
index 0000000..eb1c77a
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/mark-name.js"></script>
+<script>
+debug("");
+let worker = startWorker("resources/mark-name.js");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-now-api-expected.txt b/LayoutTests/performance-api/performance-now-api-expected.txt
new file mode 100644 (file)
index 0000000..884e878
--- /dev/null
@@ -0,0 +1,31 @@
+Basic Interface test for High Resolution Time APIs.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Performance
+PASS Performance is defined.
+PASS Performance.prototype.now is defined.
+PASS new Performance() threw exception TypeError: function is not a constructor (evaluating 'new Performance()').
+performance
+PASS performance is defined.
+PASS performance instanceof Performance is true
+PASS typeof performance.now() === "number" is true
+PASS performance.now() <= performance.now() is true
+PASS delta >= 95 && delta <= 120 is true
+
+Starting worker: resources/now-api.js
+[Worker] Performance
+PASS [Worker] Performance is defined.
+PASS [Worker] Performance.prototype.now is defined.
+PASS [Worker] new Performance() threw exception TypeError: function is not a constructor (evaluating 'new Performance()').
+[Worker] performance
+PASS [Worker] performance is defined.
+PASS [Worker] performance instanceof Performance is true
+PASS [Worker] typeof performance.now() === "number" is true
+PASS [Worker] performance.now() <= performance.now() is true
+PASS [Worker] delta >= 95 && delta <= 120 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-now-api.html b/LayoutTests/performance-api/performance-now-api.html
new file mode 100644 (file)
index 0000000..a72e99f
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/now-api.js"></script>
+<script>
+function testWorker() {
+    debug("");
+    let worker = startWorker("resources/now-api.js");
+}
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/performance-api/performance-now-time-origin-in-worker-expected.txt b/LayoutTests/performance-api/performance-now-time-origin-in-worker-expected.txt
new file mode 100644 (file)
index 0000000..e7e066b
--- /dev/null
@@ -0,0 +1,11 @@
+Ensure time origin in Worker starts from the moment of Worker Creation
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Starting worker: resources/time-origin-in-worker.js
+PASS [Worker] performance.now() < 200 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/performance-now-time-origin-in-worker.html b/LayoutTests/performance-api/performance-now-time-origin-in-worker.html
new file mode 100644 (file)
index 0000000..0fbc96b
--- /dev/null
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Ensure time origin in Worker starts from the moment of Worker Creation");
+self.jsTestIsAsync = true;
+
+while (performance.now() < 200)
+    continue;
+
+let worker = startWorker("resources/time-origin-in-worker.js");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index 28efd87..2accbe1 100644 (file)
@@ -29,6 +29,34 @@ 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()').
+
+Starting worker: resources/observer-api.js
+[Worker] PerformanceObserver
+PASS [Worker] PerformanceObserver is defined.
+PASS [Worker] PerformanceObserver.prototype.observe is defined.
+PASS [Worker] PerformanceObserver.prototype.disconnect is defined.
+PASS [Worker] PerformanceObserver() threw exception TypeError: Constructor requires 'new' operator.
+PASS [Worker] new PerformanceObserver() threw exception TypeError: Not enough arguments.
+PASS [Worker] new PerformanceObserver(1) threw exception TypeError: Argument 1 ('callback') to the PerformanceObserver constructor must be a function.
+PASS [Worker] observer = new PerformanceObserver(function() {}) did not throw exception.
+PASS [Worker] observer.observe() threw exception TypeError: Not enough arguments.
+PASS [Worker] observer.observe("mark") threw exception TypeError: Type error.
+PASS [Worker] observer.observe({}) threw exception TypeError: Member PerformanceObserverInit.entryTypes is required and must be an instance of sequence.
+PASS [Worker] observer.observe({entryTypes:"mark"}) threw exception TypeError: Value is not a sequence.
+PASS [Worker] observer.observe({entryTypes:[]}) threw exception TypeError: entryTypes cannot be an empty list.
+PASS [Worker] observer.observe({entryTypes:["not-real"]}) threw exception TypeError: entryTypes contained only unsupported types.
+PASS [Worker] observer.observe({entryTypes:["mark"]}) did not throw exception.
+PASS [Worker] observer.observe({entryTypes:["mark", "not-real"]}) did not throw exception.
+PASS [Worker] observer.observe({entryTypes:["mark", "measure"]}) did not throw exception.
+PASS [Worker] observer.disconnect() did not throw exception.
+PASS [Worker] observer.disconnect() did not throw exception.
+[Worker] 
+[Worker] PerformanceObserverEntryList
+PASS [Worker] PerformanceObserverEntryList is defined.
+PASS [Worker] PerformanceObserverEntryList.prototype.getEntries is defined.
+PASS [Worker] PerformanceObserverEntryList.prototype.getEntriesByType is defined.
+PASS [Worker] PerformanceObserverEntryList.prototype.getEntriesByName is defined.
+PASS [Worker] new PerformanceObserverEntryList() threw exception TypeError: function is not a constructor (evaluating 'new PerformanceObserverEntryList()').
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 648bc45..1d4b62e 100644 (file)
@@ -4,36 +4,10 @@
 <script src="../resources/js-test-pre.js"></script>
 </head>
 <body>
+<script src="resources/observer-api.js"></script>
 <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()`);
+let worker = startWorker("resources/observer-api.js");
 </script>
 <script src="../resources/js-test-post.js"></script>
 </body>
index 2b45ed7..17bdfd9 100644 (file)
@@ -46,6 +46,51 @@ 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
+
+Starting worker: resources/observer-basic.js
+[Worker] Inside PerformanceObserver callback
+PASS [Worker] argumentsLength === 2 is true
+PASS [Worker] list instanceof PerformanceObserverEntryList is true
+PASS [Worker] obs instanceof PerformanceObserver is true
+PASS [Worker] obs === observer is true
+FAIL [Worker] thisObject instanceof PerformanceObserver should be true. Was false.
+FAIL [Worker] thisObject === observer should be true. Was false.
+[Worker] 
+[Worker] PerformanceObserverEntryList APIs
+PASS [Worker] list.getEntries() instanceof Array is true
+PASS [Worker] list.getEntries().length === 2 is true
+PASS [Worker] list.getEntries()[0] instanceof PerformanceEntry is true
+PASS [Worker] list.getEntries()[0].name is "mark3"
+PASS [Worker] list.getEntries()[1].name is "mark4"
+PASS [Worker] list.getEntries()[0].startTime <= list.getEntries()[1].startTime is true
+PASS [Worker] list.getEntriesByType() threw exception TypeError: Not enough arguments.
+PASS [Worker] list.getEntriesByType("not-real").length === 0 is true
+PASS [Worker] list.getEntriesByType("mark").length === 2 is true
+PASS [Worker] list.getEntriesByType("mark")[0] instanceof PerformanceEntry is true
+PASS [Worker] list.getEntriesByType("mark")[0].name is "mark3"
+PASS [Worker] list.getEntriesByType("mark")[1].name is "mark4"
+PASS [Worker] list.getEntriesByName() threw exception TypeError: Not enough arguments.
+PASS [Worker] list.getEntriesByName("not-real").length === 0 is true
+PASS [Worker] list.getEntriesByName("mark1").length === 0 is true
+PASS [Worker] list.getEntriesByName("mark3").length === 1 is true
+PASS [Worker] list.getEntriesByName("mark3")[0] instanceof PerformanceEntry is true
+PASS [Worker] list.getEntriesByName("mark3")[0].name is "mark3"
+PASS [Worker] list.getEntriesByName("mark4").length === 1 is true
+PASS [Worker] list.getEntriesByName("mark4")[0] instanceof PerformanceEntry is true
+PASS [Worker] list.getEntriesByName("mark4")[0].name is "mark4"
+PASS [Worker] list.getEntriesByName() threw exception TypeError: Not enough arguments.
+PASS [Worker] list.getEntriesByName("not-real").length === 0 is true
+PASS [Worker] list.getEntriesByName("mark1").length === 0 is true
+PASS [Worker] list.getEntriesByName("mark3").length === 1 is true
+PASS [Worker] list.getEntriesByName("mark3")[0] instanceof PerformanceEntry is true
+PASS [Worker] list.getEntriesByName("mark3")[0].name is "mark3"
+PASS [Worker] list.getEntriesByName("mark4").length === 1 is true
+PASS [Worker] list.getEntriesByName("mark4")[0] instanceof PerformanceEntry is true
+PASS [Worker] list.getEntriesByName("mark4")[0].name is "mark4"
+PASS [Worker] list.getEntriesByName("mark3", "not-real").length === 0 is true
+PASS [Worker] list.getEntriesByName("mark3", "mark").length === 1 is true
+PASS [Worker] list.getEntriesByName(null, "mark").length === 0 is true
+PASS [Worker] list.getEntriesByName(undefined, "mark").length === 0 is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 6b0f6d6..093a016 100644 (file)
@@ -4,91 +4,12 @@
 <script src="../resources/js-test-pre.js"></script>
 </head>
 <body>
+<script src="resources/observer-basic.js"></script>
 <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`);
-
+function testWorker() {
     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");
+    let worker = startWorker("resources/observer-basic.js");
+}
 </script>
 <script src="../resources/js-test-post.js"></script>
 </body>
index e3f2076..48806d1 100644 (file)
@@ -42,6 +42,47 @@ PASS typeof performance.getEntriesByName("test")[0].startTime === "number" is tr
 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
+
+Starting worker: resources/timeline-api.js
+[Worker] PerformanceEntry
+PASS [Worker] PerformanceEntry is defined.
+PASS [Worker] "name" in PerformanceEntry.prototype is true
+PASS [Worker] "entryType" in PerformanceEntry.prototype is true
+PASS [Worker] "startTime" in PerformanceEntry.prototype is true
+PASS [Worker] "duration" in PerformanceEntry.prototype is true
+PASS [Worker] new PerformanceEntry() threw exception TypeError: function is not a constructor (evaluating 'new PerformanceEntry()').
+[Worker] 
+[Worker] Performance extensions
+PASS [Worker] Performance.prototype.getEntries is defined.
+PASS [Worker] Performance.prototype.getEntriesByType is defined.
+PASS [Worker] Performance.prototype.getEntriesByName is defined.
+PASS [Worker] performance.getEntries() instanceof Array is true
+PASS [Worker] performance.getEntries().length === 0 is true
+PASS [Worker] performance.mark("test"); did not throw exception.
+PASS [Worker] performance.getEntries().length === 1 is true
+PASS [Worker] performance.getEntries()[0] instanceof PerformanceEntry is true
+PASS [Worker] performance.getEntries()[0].name is "test"
+PASS [Worker] performance.getEntries()[0].entryType is "mark"
+PASS [Worker] typeof performance.getEntries()[0].startTime === "number" is true
+PASS [Worker] typeof performance.getEntries()[0].duration === "number" is true
+PASS [Worker] performance.getEntriesByType() threw exception TypeError: Not enough arguments.
+PASS [Worker] performance.getEntriesByType("not-real").length === 0 is true
+PASS [Worker] performance.getEntriesByType("mark").length === 1 is true
+PASS [Worker] performance.getEntriesByType("mark")[0] instanceof PerformanceEntry is true
+PASS [Worker] performance.getEntriesByType("mark")[0].name is "test"
+PASS [Worker] performance.getEntriesByType("mark")[0].entryType is "mark"
+PASS [Worker] typeof performance.getEntriesByType("mark")[0].startTime === "number" is true
+PASS [Worker] typeof performance.getEntriesByType("mark")[0].duration === "number" is true
+PASS [Worker] performance.getEntriesByName() threw exception TypeError: Not enough arguments.
+PASS [Worker] performance.getEntriesByName("not-real").length === 0 is true
+PASS [Worker] performance.getEntriesByName("test").length === 1 is true
+PASS [Worker] performance.getEntriesByName("test")[0] instanceof PerformanceEntry is true
+PASS [Worker] performance.getEntriesByName("test")[0].name is "test"
+PASS [Worker] performance.getEntriesByName("test")[0].entryType is "mark"
+PASS [Worker] typeof performance.getEntriesByName("test")[0].startTime === "number" is true
+PASS [Worker] typeof performance.getEntriesByName("test")[0].duration === "number" is true
+PASS [Worker] performance.getEntriesByName("test", "not-real").length === 0 is true
+PASS [Worker] performance.getEntriesByName("test", "mark").length === 1 is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index e173919..3f49ca7 100644 (file)
@@ -4,54 +4,10 @@
 <script src="../resources/js-test-pre.js"></script>
 </head>
 <body>
+<script src="resources/timeline-api.js"></script>
 <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`);
+let worker = startWorker("resources/timeline-api.js");
 </script>
 <script src="../resources/js-test-post.js"></script>
 </body>
diff --git a/LayoutTests/performance-api/resources/mark-name.js b/LayoutTests/performance-api/resources/mark-name.js
new file mode 100644 (file)
index 0000000..c1af8df
--- /dev/null
@@ -0,0 +1,40 @@
+if (self.importScripts)
+    importScripts("../../resources/js-test-pre.js");
+
+self.jsTestIsAsync = true;
+
+if (self.window)
+    description("Tests performance.mark name restrictions apply only in Window.");
+
+const reservedLegacyPerformanceTimingAttributeNames = [
+    "navigationStart",
+    "unloadEventStart",
+    "unloadEventEnd",
+    "redirectStart",
+    "redirectEnd",
+    "fetchStart",
+    "domainLookupStart",
+    "domainLookupEnd",
+    "connectStart",
+    "connectEnd",
+    "secureConnectionStart",
+    "requestStart",
+    "responseStart",
+    "responseEnd",
+    "domLoading",
+    "domInteractive",
+    "domContentLoadedEventStart",
+    "domContentLoadedEventEnd",
+    "domComplete",
+    "loadEventStart",
+    "loadEventEnd",
+];
+
+let t = self.window ? shouldThrow : shouldNotThrow;
+for (let name of reservedLegacyPerformanceTimingAttributeNames)
+    t(`performance.mark("${name}")`);
+
+shouldNotThrow(`performance.mark("mark_name")`);
+
+if (self.importScripts)
+    finishJSTest();
diff --git a/LayoutTests/performance-api/resources/now-api.js b/LayoutTests/performance-api/resources/now-api.js
new file mode 100644 (file)
index 0000000..80da0fd
--- /dev/null
@@ -0,0 +1,30 @@
+if (self.importScripts)
+    importScripts("../../resources/js-test-pre.js");
+
+self.jsTestIsAsync = true;
+
+if (self.window)
+    description("Basic Interface test for High Resolution Time APIs.");
+
+debug("Performance");
+shouldBeDefined(`Performance`);
+shouldBeDefined(`Performance.prototype.now`);
+shouldThrow(`new Performance()`);
+
+debug("performance");
+shouldBeDefined(`performance`);
+shouldBeTrue(`performance instanceof Performance`);
+shouldBeTrue(`typeof performance.now() === "number"`);
+shouldBeTrue(`performance.now() <= performance.now()`);
+
+self.time1 = performance.now();
+setTimeout(function() {
+    self.delta = performance.now() - time1;
+    // Allow for ~20ms error.
+    shouldBeTrue(`delta >= 95 && delta <= 120`);
+
+    if (self.importScripts)
+        finishJSTest();
+    else
+        testWorker();
+}, 100);
diff --git a/LayoutTests/performance-api/resources/observer-api.js b/LayoutTests/performance-api/resources/observer-api.js
new file mode 100644 (file)
index 0000000..0838790
--- /dev/null
@@ -0,0 +1,36 @@
+if (self.importScripts)
+    importScripts("../../resources/js-test-pre.js");
+
+if (self.window)
+    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()`);
+
+if (self.importScripts)
+    finishJSTest();
diff --git a/LayoutTests/performance-api/resources/observer-basic.js b/LayoutTests/performance-api/resources/observer-basic.js
new file mode 100644 (file)
index 0000000..11f385d
--- /dev/null
@@ -0,0 +1,92 @@
+if (self.importScripts)
+    importScripts("../../resources/js-test-pre.js");
+
+self.jsTestIsAsync = true;
+
+if (self.window)
+    description("Basic Behavior test for PerformanceObserver APIs.");
+
+// 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");
+self.observer = new PerformanceObserver(function(list, obs) {
+    self.argumentsLength = arguments.length;
+    self.list = list;
+    self.obs = obs;
+    self.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`);
+
+    if (self.importScripts)
+        finishJSTest();
+    else
+        testWorker();
+});
+performance.mark("mark2");
+observer.observe({entryTypes: ["mark"]});
+performance.mark("mark3");
+performance.mark("mark4");
diff --git a/LayoutTests/performance-api/resources/time-origin-in-worker.js b/LayoutTests/performance-api/resources/time-origin-in-worker.js
new file mode 100644 (file)
index 0000000..0ed3240
--- /dev/null
@@ -0,0 +1,5 @@
+importScripts("../../resources/js-test-pre.js");
+
+shouldBeTrue(`performance.now() < 200`);
+
+finishJSTest();
diff --git a/LayoutTests/performance-api/resources/timeline-api.js b/LayoutTests/performance-api/resources/timeline-api.js
new file mode 100644 (file)
index 0000000..1ef7aa5
--- /dev/null
@@ -0,0 +1,54 @@
+if (self.importScripts)
+    importScripts("../../resources/js-test-pre.js");
+
+if (self.window)
+    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`);
+
+if (self.importScripts)
+    finishJSTest();
diff --git a/LayoutTests/performance-api/resources/user-timing-api.js b/LayoutTests/performance-api/resources/user-timing-api.js
new file mode 100644 (file)
index 0000000..e36f864
--- /dev/null
@@ -0,0 +1,32 @@
+if (self.importScripts)
+    importScripts("../../resources/js-test-pre.js");
+
+if (self.window)
+    description("Basic Interface test for user-timing APIs.");
+
+debug("PerformanceMark");
+shouldBeDefined("PerformanceMark");
+shouldThrow(`new PerformanceMark()`);
+
+debug("");
+debug("PerformanceMeasure");
+shouldBeDefined("PerformanceMeasure");
+shouldThrow(`new PerformanceMeasure()`);
+
+debug("");
+debug("Performance extensions");
+shouldBeDefined(`Performance.prototype.mark`);
+shouldBeDefined(`Performance.prototype.measure`);
+shouldBeDefined(`Performance.prototype.clearMarks`);
+shouldBeDefined(`Performance.prototype.clearMeasures`);
+shouldThrow(`performance.mark()`);
+shouldNotThrow(`performance.mark("mark_name")`);
+shouldThrow(`performance.measure()`);
+shouldNotThrow(`performance.measure("measure_name")`);
+shouldNotThrow(`performance.clearMarks()`);
+shouldNotThrow(`performance.clearMarks("mark_name")`);
+shouldNotThrow(`performance.clearMeasures()`);
+shouldNotThrow(`performance.clearMeasures("measure_name")`);
+
+if (self.importScripts)
+    finishJSTest();
diff --git a/LayoutTests/performance-api/user-timing-apis-expected.txt b/LayoutTests/performance-api/user-timing-apis-expected.txt
new file mode 100644 (file)
index 0000000..c56a549
--- /dev/null
@@ -0,0 +1,53 @@
+Basic Interface test for user-timing APIs.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PerformanceMark
+PASS PerformanceMark is defined.
+PASS new PerformanceMark() threw exception TypeError: function is not a constructor (evaluating 'new PerformanceMark()').
+
+PerformanceMeasure
+PASS PerformanceMeasure is defined.
+PASS new PerformanceMeasure() threw exception TypeError: function is not a constructor (evaluating 'new PerformanceMeasure()').
+
+Performance extensions
+PASS Performance.prototype.mark is defined.
+PASS Performance.prototype.measure is defined.
+PASS Performance.prototype.clearMarks is defined.
+PASS Performance.prototype.clearMeasures is defined.
+PASS performance.mark() threw exception TypeError: Not enough arguments.
+PASS performance.mark("mark_name") did not throw exception.
+PASS performance.measure() threw exception TypeError: Not enough arguments.
+PASS performance.measure("measure_name") did not throw exception.
+PASS performance.clearMarks() did not throw exception.
+PASS performance.clearMarks("mark_name") did not throw exception.
+PASS performance.clearMeasures() did not throw exception.
+PASS performance.clearMeasures("measure_name") did not throw exception.
+
+Starting worker: resources/user-timing-api.js
+[Worker] PerformanceMark
+PASS [Worker] PerformanceMark is defined.
+PASS [Worker] new PerformanceMark() threw exception TypeError: function is not a constructor (evaluating 'new PerformanceMark()').
+[Worker] 
+[Worker] PerformanceMeasure
+PASS [Worker] PerformanceMeasure is defined.
+PASS [Worker] new PerformanceMeasure() threw exception TypeError: function is not a constructor (evaluating 'new PerformanceMeasure()').
+[Worker] 
+[Worker] Performance extensions
+PASS [Worker] Performance.prototype.mark is defined.
+PASS [Worker] Performance.prototype.measure is defined.
+PASS [Worker] Performance.prototype.clearMarks is defined.
+PASS [Worker] Performance.prototype.clearMeasures is defined.
+PASS [Worker] performance.mark() threw exception TypeError: Not enough arguments.
+PASS [Worker] performance.mark("mark_name") did not throw exception.
+PASS [Worker] performance.measure() threw exception TypeError: Not enough arguments.
+PASS [Worker] performance.measure("measure_name") did not throw exception.
+PASS [Worker] performance.clearMarks() did not throw exception.
+PASS [Worker] performance.clearMarks("mark_name") did not throw exception.
+PASS [Worker] performance.clearMeasures() did not throw exception.
+PASS [Worker] performance.clearMeasures("measure_name") did not throw exception.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/performance-api/user-timing-apis.html b/LayoutTests/performance-api/user-timing-apis.html
new file mode 100644 (file)
index 0000000..6aa2ea5
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/user-timing-api.js"></script>
+<script>
+debug("");
+let worker = startWorker("resources/user-timing-api.js");
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index 6b18daa..8a72bda 100644 (file)
@@ -587,6 +587,7 @@ set(WebCore_NON_SVG_IDL_FILES
     page/DOMWindow.idl
     page/EventSource.idl
     page/GlobalCrypto.idl
+    page/GlobalPerformance.idl
     page/History.idl
     page/IntersectionObserver.idl
     page/IntersectionObserverCallback.idl
index 6f6a04e..8094ee1 100644 (file)
@@ -1,3 +1,82 @@
+2017-02-02  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Support Performance API (performance.now(), UserTiming) in Workers
+        https://bugs.webkit.org/show_bug.cgi?id=167717
+
+        Reviewed by Ryosuke Niwa.
+
+        Tests: performance-api/performance-mark-name.html
+               performance-api/performance-now-api.html
+               performance-api/performance-now-time-origin-in-worker.html
+               performance-api/user-timing-apis.html
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        New files.
+
+        * page/DOMWindow.idl:
+        * page/GlobalPerformance.idl:
+        * workers/WorkerGlobalScope.idl:
+        Add partial interface for performance attribute.
+
+        * page/Performance.idl:
+        * page/PerformanceEntry.idl:
+        * page/PerformanceMark.idl:
+        * page/PerformanceMeasure.idl:
+        * page/PerformanceObserver.idl:
+        * page/PerformanceObserverEntryList.idl:
+        Expose these to Workers.
+
+        * page/Performance.cpp:
+        (WebCore::Performance::Performance):
+        (WebCore::Performance::contextDestroyed):
+        * page/Performance.h:
+        Use the EventQueue variant that works with any ScriptExectionContext.
+
+        * page/PerformanceObserver.cpp:
+        (WebCore::PerformanceObserver::PerformanceObserver):
+        Get the Performance base in a Worker context.
+
+        * page/PerformanceUserTiming.cpp:
+        (WebCore::UserTiming::mark):
+        Only reject legacy special mark names in a Window, not a Worker.
+
+        (WebCore::UserTiming::findExistingMarkStartTime):
+        Simple implementation returns 0 as the start time in Workers. The spec
+        is currently imprecise here, but it does not have the unusual
+        PerformanceTiming behavior in a Window which is part of User Timing 1.
+
+        * workers/Worker.cpp:
+        (WebCore::Worker::create):
+        (WebCore::Worker::notifyFinished):
+        * workers/Worker.h:
+        Record the moment of Worker creation.
+
+        * workers/WorkerGlobalScope.cpp:
+        (WebCore::WorkerGlobalScope::WorkerGlobalScope):
+        (WebCore::WorkerGlobalScope::performance):
+        * workers/WorkerGlobalScope.h:
+        Construct the Performance object with the moment of creation (timeOrigin).
+
+        * workers/DedicatedWorkerGlobalScope.cpp:
+        (WebCore::DedicatedWorkerGlobalScope::create):
+        (WebCore::DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope):
+        * workers/DedicatedWorkerGlobalScope.h:
+        * workers/DedicatedWorkerThread.cpp:
+        (WebCore::DedicatedWorkerThread::DedicatedWorkerThread):
+        (WebCore::DedicatedWorkerThread::createWorkerGlobalScope):
+        * workers/DedicatedWorkerThread.h:
+        * workers/WorkerGlobalScopeProxy.h:
+        * workers/WorkerMessagingProxy.cpp:
+        (WebCore::WorkerMessagingProxy::startWorkerGlobalScope):
+        * workers/WorkerMessagingProxy.h:
+        * workers/WorkerThread.cpp:
+        (WebCore::WorkerThreadStartupData::WorkerThreadStartupData):
+        (WebCore::WorkerThread::WorkerThread):
+        (WebCore::WorkerThread::workerThread):
+        * workers/WorkerThread.h:
+        Pass the moment of creation (timeOrigin) through to WorkerGlobalScope creation.
+
 2017-02-02  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r211579.
index 71066c6..797de78 100644 (file)
@@ -569,6 +569,7 @@ JS_BINDING_IDLS = \
     $(WebCore)/page/DOMWindow.idl \
     $(WebCore)/page/EventSource.idl \
     $(WebCore)/page/GlobalCrypto.idl \
+    $(WebCore)/page/GlobalPerformance.idl \
     $(WebCore)/page/History.idl \
     $(WebCore)/page/IntersectionObserver.idl \
     $(WebCore)/page/IntersectionObserverCallback.idl \
index f7a51d6..1d5a7bc 100644 (file)
 
     [CallWith=ScriptState&CallerWindow, DoNotCheckSecurity, ForwardDeclareInHeader, MayThrowException] void postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
 
-    [Conditional=WEB_TIMING, Replaceable] readonly attribute Performance performance;
-
     long requestAnimationFrame(RequestAnimationFrameCallback callback);
     void cancelAnimationFrame(long id);
     long webkitRequestAnimationFrame(RequestAnimationFrameCallback callback);
 
 DOMWindow implements GlobalCrypto;
 DOMWindow implements GlobalEventHandlers;
+DOMWindow implements GlobalPerformance;
 DOMWindow implements WindowEventHandlers;
 DOMWindow implements WindowOrWorkerGlobalScope;
diff --git a/Source/WebCore/page/GlobalPerformance.idl b/Source/WebCore/page/GlobalPerformance.idl
new file mode 100644 (file)
index 0000000..298ab52
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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. ``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
+ * 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/hr-time/
+
+[
+    NoInterfaceObject,
+    Exposed=(Window,Worker)
+] interface GlobalPerformance {
+    [Conditional=WEB_TIMING, Replaceable] readonly attribute Performance performance;
+};
index 5b43309..25c1b46 100644 (file)
@@ -54,6 +54,7 @@ namespace WebCore {
 Performance::Performance(ScriptExecutionContext& context, double timeOrigin)
     : ContextDestructionObserver(&context)
     , m_timeOrigin(timeOrigin)
+    , m_performanceTimelineTaskQueue(context)
 {
     ASSERT(m_timeOrigin);
 }
@@ -62,6 +63,13 @@ Performance::~Performance()
 {
 }
 
+void Performance::contextDestroyed()
+{
+    m_performanceTimelineTaskQueue.close();
+
+    ContextDestructionObserver::contextDestroyed();
+}
+
 double Performance::now() const
 {
     double nowSeconds = monotonicallyIncreasingTime() - m_timeOrigin;
index b43fcc2..cb7f3d2 100644 (file)
@@ -90,6 +90,8 @@ public:
 private:
     Performance(ScriptExecutionContext&, double timeOrigin);
 
+    void contextDestroyed() override;
+
     EventTargetInterface eventTargetInterface() const final { return PerformanceEventTargetInterfaceType; }
 
     void refEventTarget() final { ref(); }
@@ -110,7 +112,7 @@ private:
 
     std::unique_ptr<UserTiming> m_userTiming;
 
-    GenericTaskQueue<Timer> m_performanceTimelineTaskQueue;
+    GenericTaskQueue<ScriptExecutionContext> m_performanceTimelineTaskQueue;
     ListHashSet<RefPtr<PerformanceObserver>> m_observers;
 };
 
index 1b384ed..47059b9 100644 (file)
@@ -35,6 +35,7 @@ typedef double DOMHighResTimeStamp;
 
 [
     Conditional=WEB_TIMING,
+    Exposed=(Window,Worker),
     GenerateIsReachable=ImplScriptExecutionContext,
 ] interface Performance : EventTarget {
 
index 32dffc3..47d317c 100644 (file)
@@ -34,8 +34,9 @@ typedef double DOMHighResTimeStamp;
 
 [
     Conditional=WEB_TIMING,
-    EnabledAtRuntime=PerformanceTimeline,
     CustomToJSObject,
+    EnabledAtRuntime=PerformanceTimeline,
+    Exposed=(Window,Worker),
 ] interface PerformanceEntry {
     readonly attribute DOMString name;
     readonly attribute DOMString entryType;
index 446682a..be44db0 100644 (file)
@@ -28,5 +28,6 @@
 [
     Conditional=WEB_TIMING,
     EnabledAtRuntime=UserTiming,
+    Exposed=(Window,Worker),
 ] interface PerformanceMark : PerformanceEntry {
 };
index f8676b0..60199db 100644 (file)
@@ -28,5 +28,6 @@
 [
     Conditional=WEB_TIMING,
     EnabledAtRuntime=UserTiming,
+    Exposed=(Window,Worker),
 ] interface PerformanceMeasure : PerformanceEntry {
 };
index 44ae3f5..8d4bfa9 100644 (file)
@@ -45,7 +45,8 @@ PerformanceObserver::PerformanceObserver(ScriptExecutionContext& scriptExecution
         if (DOMWindow* window = document.domWindow())
             m_performance = window->performance();
     } else if (is<WorkerGlobalScope>(scriptExecutionContext)) {
-        // FIXME: Support Performance Timeline for Workers.
+        auto& workerGlobalScope = downcast<WorkerGlobalScope>(scriptExecutionContext);
+        m_performance = &workerGlobalScope.performance();
     } else
         ASSERT_NOT_REACHED();
 }
index 588334e..9717812 100644 (file)
@@ -30,6 +30,7 @@
     Constructor(PerformanceObserverCallback callback),
     ConstructorCallWith=ScriptExecutionContext,
     EnabledAtRuntime=PerformanceTimeline,
+    Exposed=(Window,Worker),
     ImplementationLacksVTable,
 ] interface PerformanceObserver {
     [MayThrowException] void observe(PerformanceObserverInit options);
index 0ee7040..a28cbb5 100644 (file)
@@ -28,6 +28,7 @@
 [
     Conditional=WEB_TIMING,
     EnabledAtRuntime=PerformanceTimeline,
+    Exposed=(Window,Worker),
     ImplementationLacksVTable,
 ] interface PerformanceObserverEntryList {
     PerformanceEntryList getEntries();
index dcb057a..6c933d8 100644 (file)
 
 #if ENABLE(WEB_TIMING)
 
+#include "Document.h"
 #include "ExceptionCode.h"
 #include "Performance.h"
 #include "PerformanceTiming.h"
 #include <array>
+#include <wtf/MainThread.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/dtoa/utils.h>
 
@@ -43,7 +45,8 @@ typedef unsigned long long (PerformanceTiming::*NavigationTimingFunction)() cons
 
 static NavigationTimingFunction restrictedMarkFunction(const String& markName)
 {
-    // FIXME: Update this list when moving to Navigation Timing Level 2.
+    ASSERT(isMainThread());
+
     using MapPair = std::pair<ASCIILiteral, NavigationTimingFunction>;
     static const std::array<MapPair, 21> pairs = { {
         MapPair { ASCIILiteral("navigationStart"), &PerformanceTiming::navigationStart },
@@ -97,8 +100,10 @@ static void clearPerformanceEntries(PerformanceEntryMap& performanceEntryMap, co
 
 ExceptionOr<Ref<PerformanceMark>> UserTiming::mark(const String& markName)
 {
-    if (restrictedMarkFunction(markName))
-        return Exception { SYNTAX_ERR };
+    if (is<Document>(m_performance.scriptExecutionContext())) {
+        if (restrictedMarkFunction(markName))
+            return Exception { SYNTAX_ERR };
+    }
 
     auto& performanceEntryList = m_marksMap.ensure(markName, [] { return Vector<RefPtr<PerformanceEntry>>(); }).iterator->value;
     auto entry = PerformanceMark::create(markName, m_performance.now());
@@ -116,17 +121,15 @@ ExceptionOr<double> UserTiming::findExistingMarkStartTime(const String& markName
     if (m_marksMap.contains(markName))
         return m_marksMap.get(markName).last()->startTime();
 
+    PerformanceTiming* timing = m_performance.timing();
+    if (!timing)
+        return 0.0;
+
     if (auto function = restrictedMarkFunction(markName)) {
-        if (PerformanceTiming* timing = m_performance.timing()) {
-            double value = static_cast<double>(((*timing).*(function))());
-            if (!value)
-                return Exception { INVALID_ACCESS_ERR };
-            return value - timing->navigationStart();
-        } else {
-            // FIXME: Support UserTiming in Workers.
-            ASSERT_NOT_REACHED();
-            return Exception { SYNTAX_ERR };
-        }
+        double value = static_cast<double>(((*timing).*(function))());
+        if (!value)
+            return Exception { INVALID_ACCESS_ERR };
+        return value - timing->navigationStart();
     }
 
     return Exception { SYNTAX_ERR };
index 0c67fdf..3fbb2e7 100644 (file)
 
 namespace WebCore {
 
-Ref<DedicatedWorkerGlobalScope> DedicatedWorkerGlobalScope::create(const URL& url, const String& identifier, const String& userAgent, DedicatedWorkerThread& thread, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
+Ref<DedicatedWorkerGlobalScope> DedicatedWorkerGlobalScope::create(const URL& url, const String& identifier, const String& userAgent, DedicatedWorkerThread& thread, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
 {
-    auto context = adoptRef(*new DedicatedWorkerGlobalScope(url, identifier, userAgent, thread, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), connectionProxy, socketProvider));
+    auto context = adoptRef(*new DedicatedWorkerGlobalScope(url, identifier, userAgent, thread, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), timeOrigin, connectionProxy, socketProvider));
     if (!shouldBypassMainWorldContentSecurityPolicy)
         context->applyContentSecurityPolicyResponseHeaders(contentSecurityPolicyResponseHeaders);
     return context;
 }
 
-DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, DedicatedWorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
-    : WorkerGlobalScope(url, identifier, userAgent, thread, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), connectionProxy, socketProvider)
+DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, DedicatedWorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
+    : WorkerGlobalScope(url, identifier, userAgent, thread, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), timeOrigin, connectionProxy, socketProvider)
 {
 }
 
index 656d67b..2f7594e 100644 (file)
@@ -48,7 +48,7 @@ class SerializedScriptValue;
 
 class DedicatedWorkerGlobalScope final : public WorkerGlobalScope {
 public:
-    static Ref<DedicatedWorkerGlobalScope> create(const URL&, const String& identifier, const String& userAgent, DedicatedWorkerThread&, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*);
+    static Ref<DedicatedWorkerGlobalScope> create(const URL&, const String& identifier, const String& userAgent, DedicatedWorkerThread&, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*);
     virtual ~DedicatedWorkerGlobalScope();
 
     ExceptionOr<void> postMessage(JSC::ExecState&, JSC::JSValue message, Vector<JSC::Strong<JSC::JSObject>>&&);
@@ -58,7 +58,7 @@ public:
 private:
     using Base = WorkerGlobalScope;
 
-    DedicatedWorkerGlobalScope(const URL&, const String& identifier, const String& userAgent, DedicatedWorkerThread&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*);
+    DedicatedWorkerGlobalScope(const URL&, const String& identifier, const String& userAgent, DedicatedWorkerThread&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*);
 
     bool isDedicatedWorkerGlobalScope() const final { return true; }
     ExceptionOr<void> importScripts(const Vector<String>& urls) final;
index bd2fac5..cbf459e 100644 (file)
@@ -38,8 +38,8 @@
 
 namespace WebCore {
 
-DedicatedWorkerThread::DedicatedWorkerThread(const URL& url, const String& identifier, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerObjectProxy& workerObjectProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags)
-    : WorkerThread(url, identifier, userAgent, sourceCode, workerLoaderProxy, workerObjectProxy, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin, connectionProxy, socketProvider, runtimeFlags)
+DedicatedWorkerThread::DedicatedWorkerThread(const URL& url, const String& identifier, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerObjectProxy& workerObjectProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags)
+    : WorkerThread(url, identifier, userAgent, sourceCode, workerLoaderProxy, workerObjectProxy, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin, timeOrigin, connectionProxy, socketProvider, runtimeFlags)
     , m_workerObjectProxy(workerObjectProxy)
 {
 }
@@ -48,9 +48,9 @@ DedicatedWorkerThread::~DedicatedWorkerThread()
 {
 }
 
-Ref<WorkerGlobalScope> DedicatedWorkerThread::createWorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin)
+Ref<WorkerGlobalScope> DedicatedWorkerThread::createWorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, double timeOrigin)
 {
-    return DedicatedWorkerGlobalScope::create(url, identifier, userAgent, *this, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), idbConnectionProxy(), socketProvider());
+    return DedicatedWorkerGlobalScope::create(url, identifier, userAgent, *this, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), timeOrigin, idbConnectionProxy(), socketProvider());
 }
 
 void DedicatedWorkerThread::runEventLoop()
index 24789d9..8ff8a62 100644 (file)
@@ -49,11 +49,11 @@ public:
     WorkerObjectProxy& workerObjectProxy() const { return m_workerObjectProxy; }
 
 protected:
-    Ref<WorkerGlobalScope> createWorkerGlobalScope(const URL&, const String& identifier, const String& userAgent, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin) override;
+    Ref<WorkerGlobalScope> createWorkerGlobalScope(const URL&, const String& identifier, const String& userAgent, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, double timeOrigin) override;
     void runEventLoop() override;
 
 private:
-    DedicatedWorkerThread(const URL&, const String& identifier, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerObjectProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*, JSC::RuntimeFlags);
+    DedicatedWorkerThread(const URL&, const String& identifier, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerObjectProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*, JSC::RuntimeFlags);
 
     WorkerObjectProxy& m_workerObjectProxy;
 };
index 7cec872..9037e1c 100644 (file)
@@ -87,6 +87,9 @@ ExceptionOr<Ref<Worker>> Worker::create(ScriptExecutionContext& context, const S
     // The worker context does not exist while loading, so we must ensure that the worker object is not collected, nor are its event listeners.
     worker->setPendingActivity(worker.ptr());
 
+    // https://html.spec.whatwg.org/multipage/workers.html#official-moment-of-creation
+    worker->m_momentOfCreation = monotonicallyIncreasingTime();
+
     worker->m_scriptLoader = WorkerScriptLoader::create();
     auto contentSecurityPolicyEnforcement = shouldBypassMainWorldContentSecurityPolicy ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceChildSrcDirective;
     worker->m_scriptLoader->loadAsynchronously(&context, scriptURL.releaseReturnValue(), FetchOptions::Mode::SameOrigin, contentSecurityPolicyEnforcement, worker->m_identifier, worker.ptr());
@@ -161,7 +164,7 @@ void Worker::notifyFinished()
         dispatchEvent(Event::create(eventNames().errorEvent, false, true));
     else {
         const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders = m_contentSecurityPolicyResponseHeaders ? m_contentSecurityPolicyResponseHeaders.value() : scriptExecutionContext()->contentSecurityPolicy()->responseHeaders();
-        m_contextProxy.startWorkerGlobalScope(m_scriptLoader->url(), scriptExecutionContext()->userAgent(m_scriptLoader->url()), m_scriptLoader->script(), contentSecurityPolicyResponseHeaders, m_shouldBypassMainWorldContentSecurityPolicy, m_runtimeFlags);
+        m_contextProxy.startWorkerGlobalScope(m_scriptLoader->url(), scriptExecutionContext()->userAgent(m_scriptLoader->url()), m_scriptLoader->script(), contentSecurityPolicyResponseHeaders, m_shouldBypassMainWorldContentSecurityPolicy, m_momentOfCreation, m_runtimeFlags);
         InspectorInstrumentation::scriptImported(*scriptExecutionContext(), m_scriptLoader->identifier(), m_scriptLoader->script());
     }
     m_scriptLoader = nullptr;
index e174a29..f4b0915 100644 (file)
@@ -82,6 +82,7 @@ private:
     String m_identifier;
     WorkerGlobalScopeProxy& m_contextProxy; // The proxy outlives the worker to perform thread shutdown.
     std::optional<ContentSecurityPolicyResponseHeaders> m_contentSecurityPolicyResponseHeaders;
+    double m_momentOfCreation { 0 };
     bool m_shouldBypassMainWorldContentSecurityPolicy { false };
     JSC::RuntimeFlags m_runtimeFlags;
 };
index bf2c4c7..b3eb2e1 100644 (file)
@@ -33,6 +33,7 @@
 #include "ExceptionCode.h"
 #include "IDBConnectionProxy.h"
 #include "InspectorInstrumentation.h"
+#include "Performance.h"
 #include "ScheduledAction.h"
 #include "ScriptSourceCode.h"
 #include "SecurityOrigin.h"
@@ -52,7 +53,7 @@ using namespace Inspector;
 
 namespace WebCore {
 
-WorkerGlobalScope::WorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, WorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
+WorkerGlobalScope::WorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, WorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
     : m_url(url)
     , m_identifier(identifier)
     , m_userAgent(userAgent)
@@ -68,6 +69,9 @@ WorkerGlobalScope::WorkerGlobalScope(const URL& url, const String& identifier, c
 #if ENABLE(WEB_SOCKETS)
     , m_socketProvider(socketProvider)
 #endif
+#if ENABLE(WEB_TIMING)
+    , m_performance(Performance::create(*this, timeOrigin))
+#endif
 {
 #if !ENABLE(INDEXED_DATABASE)
     UNUSED_PARAM(connectionProxy);
@@ -347,4 +351,13 @@ Crypto& WorkerGlobalScope::crypto()
     return *m_crypto;
 }
 
+#if ENABLE(WEB_TIMING)
+
+Performance& WorkerGlobalScope::performance() const
+{
+    return m_performance;
+}
+
+#endif
+
 } // namespace WebCore
index 45e4fe7..39c17d0 100644 (file)
@@ -39,6 +39,7 @@ namespace WebCore {
 
 class ContentSecurityPolicyResponseHeaders;
 class Crypto;
+class Performance;
 class ScheduledAction;
 class WorkerInspectorController;
 class WorkerLocation;
@@ -99,8 +100,12 @@ public:
 
     Crypto& crypto();
 
+#if ENABLE(WEB_TIMING)
+    Performance& performance() const;
+#endif
+
 protected:
-    WorkerGlobalScope(const URL&, const String& identifier, const String& userAgent, WorkerThread&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*);
+    WorkerGlobalScope(const URL&, const String& identifier, const String& userAgent, WorkerThread&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*);
 
     void applyContentSecurityPolicyResponseHeaders(const ContentSecurityPolicyResponseHeaders&);
 
@@ -171,6 +176,10 @@ private:
     RefPtr<SocketProvider> m_socketProvider;
 #endif
 
+#if ENABLE(WEB_TIMING)
+    Ref<Performance> m_performance;
+#endif
+
     mutable RefPtr<Crypto> m_crypto;
 };
 
index f6ade55..16a5e0a 100644 (file)
@@ -62,4 +62,5 @@
 };
 
 WorkerGlobalScope implements GlobalCrypto;
+WorkerGlobalScope implements GlobalPerformance;
 WorkerGlobalScope implements WindowOrWorkerGlobalScope;
index 05dda18..1528ff2 100644 (file)
@@ -45,7 +45,7 @@ class WorkerGlobalScopeProxy {
 public:
     static WorkerGlobalScopeProxy& create(Worker&);
 
-    virtual void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, JSC::RuntimeFlags) = 0;
+    virtual void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, double timeOrigin, JSC::RuntimeFlags) = 0;
     virtual void terminateWorkerGlobalScope() = 0;
     virtual void postMessageToWorkerGlobalScope(RefPtr<SerializedScriptValue>&&, std::unique_ptr<MessagePortChannelArray>) = 0;
     virtual bool hasPendingActivity() const = 0;
index 8bc36b7..bbc9a55 100644 (file)
@@ -67,7 +67,7 @@ WorkerMessagingProxy::~WorkerMessagingProxy()
         || (is<WorkerGlobalScope>(*m_scriptExecutionContext) && currentThread() == downcast<WorkerGlobalScope>(*m_scriptExecutionContext).thread().threadID()));
 }
 
-void WorkerMessagingProxy::startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, JSC::RuntimeFlags runtimeFlags)
+void WorkerMessagingProxy::startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, double timeOrigin, JSC::RuntimeFlags runtimeFlags)
 {
     // FIXME: This need to be revisited when we support nested worker one day
     ASSERT(m_scriptExecutionContext);
@@ -87,7 +87,7 @@ void WorkerMessagingProxy::startWorkerGlobalScope(const URL& scriptURL, const St
     SocketProvider* socketProvider = nullptr;
 #endif
 
-    auto thread = DedicatedWorkerThread::create(scriptURL, identifier, userAgent, sourceCode, *this, *this, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, document.topOrigin(), proxy, socketProvider, runtimeFlags);
+    auto thread = DedicatedWorkerThread::create(scriptURL, identifier, userAgent, sourceCode, *this, *this, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, document.topOrigin(), timeOrigin, proxy, socketProvider, runtimeFlags);
 
     workerThreadCreated(thread.get());
     thread->start();
index 1a89f2a..871478e 100644 (file)
@@ -44,7 +44,7 @@ private:
 
     // Implementations of WorkerGlobalScopeProxy.
     // (Only use these functions in the worker object thread.)
-    void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, JSC::RuntimeFlags) final;
+    void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, double timeOrigin, JSC::RuntimeFlags) final;
     void terminateWorkerGlobalScope() final;
     void postMessageToWorkerGlobalScope(RefPtr<SerializedScriptValue>&&, std::unique_ptr<MessagePortChannelArray>) final;
     bool hasPendingActivity() const final;
index bf24d50..48ab6b8 100644 (file)
@@ -72,7 +72,7 @@ unsigned WorkerThread::workerThreadCount()
 struct WorkerThreadStartupData {
     WTF_MAKE_NONCOPYABLE(WorkerThreadStartupData); WTF_MAKE_FAST_ALLOCATED;
 public:
-    WorkerThreadStartupData(const URL& scriptURL, const String& identifier, const String& userAgent, const String& sourceCode, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin);
+    WorkerThreadStartupData(const URL& scriptURL, const String& identifier, const String& userAgent, const String& sourceCode, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, double timeOrigin);
 
     URL m_scriptURL;
     String m_identifier;
@@ -82,9 +82,10 @@ public:
     ContentSecurityPolicyResponseHeaders m_contentSecurityPolicyResponseHeaders;
     bool m_shouldBypassMainWorldContentSecurityPolicy;
     Ref<SecurityOrigin> m_topOrigin;
+    double m_timeOrigin;
 };
 
-WorkerThreadStartupData::WorkerThreadStartupData(const URL& scriptURL, const String& identifier, const String& userAgent, const String& sourceCode, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin)
+WorkerThreadStartupData::WorkerThreadStartupData(const URL& scriptURL, const String& identifier, const String& userAgent, const String& sourceCode, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, double timeOrigin)
     : m_scriptURL(scriptURL.isolatedCopy())
     , m_identifier(identifier.isolatedCopy())
     , m_userAgent(userAgent.isolatedCopy())
@@ -93,15 +94,16 @@ WorkerThreadStartupData::WorkerThreadStartupData(const URL& scriptURL, const Str
     , m_contentSecurityPolicyResponseHeaders(contentSecurityPolicyResponseHeaders.isolatedCopy())
     , m_shouldBypassMainWorldContentSecurityPolicy(shouldBypassMainWorldContentSecurityPolicy)
     , m_topOrigin(topOrigin.isolatedCopy())
+    , m_timeOrigin(timeOrigin)
 {
 }
 
-WorkerThread::WorkerThread(const URL& scriptURL, const String& identifier, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags)
+WorkerThread::WorkerThread(const URL& scriptURL, const String& identifier, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags)
     : m_threadID(0)
     , m_workerLoaderProxy(workerLoaderProxy)
     , m_workerReportingProxy(workerReportingProxy)
     , m_runtimeFlags(runtimeFlags)
-    , m_startupData(std::make_unique<WorkerThreadStartupData>(scriptURL, identifier, userAgent, sourceCode, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin))
+    , m_startupData(std::make_unique<WorkerThreadStartupData>(scriptURL, identifier, userAgent, sourceCode, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin, timeOrigin))
 #if ENABLE(INDEXED_DATABASE)
     , m_idbConnectionProxy(connectionProxy)
 #endif
@@ -161,7 +163,7 @@ void WorkerThread::workerThread()
 
     {
         LockHolder lock(m_threadCreationMutex);
-        m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL, m_startupData->m_identifier, m_startupData->m_userAgent, m_startupData->m_contentSecurityPolicyResponseHeaders, m_startupData->m_shouldBypassMainWorldContentSecurityPolicy, WTFMove(m_startupData->m_topOrigin));
+        m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL, m_startupData->m_identifier, m_startupData->m_userAgent, m_startupData->m_contentSecurityPolicyResponseHeaders, m_startupData->m_shouldBypassMainWorldContentSecurityPolicy, WTFMove(m_startupData->m_topOrigin), m_startupData->m_timeOrigin);
 
         if (m_runLoop.terminated()) {
             // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet,
index 496dcc9..0cde2ad 100644 (file)
@@ -80,10 +80,10 @@ public:
     JSC::RuntimeFlags runtimeFlags() const { return m_runtimeFlags; }
 
 protected:
-    WorkerThread(const URL&, const String& identifier, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerReportingProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*, JSC::RuntimeFlags);
+    WorkerThread(const URL&, const String& identifier, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerReportingProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin& topOrigin, double timeOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*, JSC::RuntimeFlags);
 
     // Factory method for creating a new worker context for the thread.
-    virtual Ref<WorkerGlobalScope> createWorkerGlobalScope(const URL&, const String& identifier, const String& userAgent, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin) = 0;
+    virtual Ref<WorkerGlobalScope> createWorkerGlobalScope(const URL&, const String& identifier, const String& userAgent, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, double timeOrigin) = 0;
 
     // Executes the event loop for the worker thread. Derived classes can override to perform actions before/after entering the event loop.
     virtual void runEventLoop();