WebKit Bugzilla
Attachment 346275 Details for
Bug 188212
: Add self.queueMicrotask(f) on DOMWindow
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-188212-20180801232215.patch (text/plain), 16.42 KB, created by
Yusuke Suzuki
on 2018-08-01 07:22:16 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2018-08-01 07:22:16 PDT
Size:
16.42 KB
patch
obsolete
>Subversion Revision: 234455 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index cae1db4e0edbd7eca3e7a9846623130a6211b0e6..d612031a466d222e1e8b8b433a788ed270e0717f 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,25 @@ >+2018-08-01 Yusuke Suzuki <utatane.tea@gmail.com> >+ >+ Add self.queueMicrotask(f) >+ https://bugs.webkit.org/show_bug.cgi?id=188212 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch adds self.queueMicrotask(f), which takes a function and enqueue it into microtask queue. >+ >+ Tests: js/dom/queue-microtask-window.html >+ js/dom/queue-microtask-workers.html >+ >+ * page/DOMWindow.cpp: >+ (WebCore::DOMWindow::queueMicrotask): >+ * page/DOMWindow.h: >+ * page/WindowOrWorkerGlobalScope.idl: >+ Use VoidCallback for holding a function. >+ >+ * workers/WorkerGlobalScope.cpp: >+ (WebCore::WorkerGlobalScope::queueMicrotask): >+ * workers/WorkerGlobalScope.h: >+ > 2018-08-01 Zan Dobersek <zdobersek@igalia.com> > > [CoordGraphics] Move CoordinatedBackingStore to WebCore >diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp >index 813fcaf55253075f19b8122cf01c6a9434833fb1..c22c36198ab188293f82d70bd77c6e9f10fcc865 100644 >--- a/Source/WebCore/page/DOMWindow.cpp >+++ b/Source/WebCore/page/DOMWindow.cpp >@@ -27,6 +27,7 @@ > #include "config.h" > #include "DOMWindow.h" > >+#include "ActiveDOMCallbackMicrotask.h" > #include "BackForwardController.h" > #include "BarProp.h" > #include "CSSComputedStyleDeclaration.h" >@@ -73,6 +74,7 @@ > #include "MediaQueryMatcher.h" > #include "MessageEvent.h" > #include "MessageWithMessagePorts.h" >+#include "Microtasks.h" > #include "NavigationScheduler.h" > #include "Navigator.h" > #include "Page.h" >@@ -104,6 +106,7 @@ > #include "URL.h" > #include "UserGestureIndicator.h" > #include "VisualViewport.h" >+#include "VoidCallback.h" > #include "WebKitPoint.h" > #include "WindowFeatures.h" > #include "WindowFocusAllowedIndicator.h" >@@ -1764,6 +1767,17 @@ void DOMWindow::clearInterval(int timeoutId) > DOMTimer::removeById(*context, timeoutId); > } > >+void DOMWindow::queueMicrotask(Ref<VoidCallback>&& callback) >+{ >+ ScriptExecutionContext* context = scriptExecutionContext(); >+ if (!context) >+ return; >+ auto microtask = std::make_unique<ActiveDOMCallbackMicrotask>(MicrotaskQueue::mainThreadQueue(), *context, [callback = WTFMove(callback)]() { >+ callback->handleEvent(); >+ }); >+ MicrotaskQueue::mainThreadQueue().append(WTFMove(microtask)); >+} >+ > int DOMWindow::requestAnimationFrame(Ref<RequestAnimationFrameCallback>&& callback) > { > callback->m_useLegacyTimeBase = false; >diff --git a/Source/WebCore/page/DOMWindow.h b/Source/WebCore/page/DOMWindow.h >index 5c48e7cdfde465e2836a257296c9f95f780ee94f..d771d76a5b5f29f584da6eb5b5117237c467600c 100644 >--- a/Source/WebCore/page/DOMWindow.h >+++ b/Source/WebCore/page/DOMWindow.h >@@ -81,6 +81,7 @@ class StyleMedia; > class VisualViewport; > class WebKitNamespace; > class WebKitPoint; >+class VoidCallback; > > struct ImageBitmapOptions; > struct WindowFeatures; >@@ -255,6 +256,8 @@ class DOMWindow final > ExceptionOr<int> setInterval(JSC::ExecState&, std::unique_ptr<ScheduledAction>, int timeout, Vector<JSC::Strong<JSC::Unknown>>&& arguments); > void clearInterval(int timeoutId); > >+ void queueMicrotask(Ref<VoidCallback>&&); >+ > int requestAnimationFrame(Ref<RequestAnimationFrameCallback>&&); > int webkitRequestAnimationFrame(Ref<RequestAnimationFrameCallback>&&); > void cancelAnimationFrame(int id); >diff --git a/Source/WebCore/page/WindowOrWorkerGlobalScope.idl b/Source/WebCore/page/WindowOrWorkerGlobalScope.idl >index a24f42617a481ca5098e133810c71203ad8ccce0..97b0400dba24901b5e62afcfccb1512eead69d6e 100644 >--- a/Source/WebCore/page/WindowOrWorkerGlobalScope.idl >+++ b/Source/WebCore/page/WindowOrWorkerGlobalScope.idl >@@ -46,6 +46,8 @@ typedef (CanvasImageSource or Blob or ImageData) ImageBitmapSource; > [CallWith=ScriptState, MayThrowException] long setInterval(ScheduledAction handler, optional long timeout = 0, any... arguments); > void clearInterval(optional long handle = 0); > >+ void queueMicrotask(VoidCallback callback); >+ > // Base64 utility methods. > [MayThrowException] DOMString atob(DOMString string); > [MayThrowException] DOMString btoa(DOMString string); >diff --git a/Source/WebCore/workers/WorkerGlobalScope.cpp b/Source/WebCore/workers/WorkerGlobalScope.cpp >index a5b1b36eda2d68114806aaaed45c5b89796fa1fb..00529ea096c1834bd08ac095849ba7d054d080e1 100644 >--- a/Source/WebCore/workers/WorkerGlobalScope.cpp >+++ b/Source/WebCore/workers/WorkerGlobalScope.cpp >@@ -40,6 +40,7 @@ > #include "SecurityOriginPolicy.h" > #include "ServiceWorkerGlobalScope.h" > #include "SocketProvider.h" >+#include "VoidCallback.h" > #include "WorkerInspectorController.h" > #include "WorkerLoaderProxy.h" > #include "WorkerLocation.h" >@@ -250,6 +251,13 @@ void WorkerGlobalScope::clearInterval(int timeoutId) > DOMTimer::removeById(*this, timeoutId); > } > >+void WorkerGlobalScope::queueMicrotask(Ref<VoidCallback>&& callback) >+{ >+ postTask([callback = WTFMove(callback)](ScriptExecutionContext&) { >+ callback->handleEvent(); >+ }); >+} >+ > ExceptionOr<void> WorkerGlobalScope::importScripts(const Vector<String>& urls) > { > ASSERT(contentSecurityPolicy()); >diff --git a/Source/WebCore/workers/WorkerGlobalScope.h b/Source/WebCore/workers/WorkerGlobalScope.h >index bac0db88dad55278a423d9896d7806156c4df8ed..d5c1b8f436ce0bae0850a0eff8aba41eb15e0209 100644 >--- a/Source/WebCore/workers/WorkerGlobalScope.h >+++ b/Source/WebCore/workers/WorkerGlobalScope.h >@@ -50,6 +50,7 @@ class WorkerInspectorController; > class WorkerLocation; > class WorkerNavigator; > class WorkerThread; >+class VoidCallback; > > namespace IDBClient { > class IDBConnectionProxy; >@@ -98,6 +99,8 @@ class WorkerGlobalScope : public RefCounted<WorkerGlobalScope>, public Supplemen > ExceptionOr<int> setInterval(JSC::ExecState&, std::unique_ptr<ScheduledAction>, int timeout, Vector<JSC::Strong<JSC::Unknown>>&& arguments); > void clearInterval(int timeoutId); > >+ void queueMicrotask(Ref<VoidCallback>&&); >+ > bool isContextThread() const final; > bool isSecureContext() const final; > >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 22e95870bae2806684ef92d0f20b005b1cb2a817..b352479fcd099157533550a6c90da61bf6fea179 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,19 @@ >+2018-08-01 Yusuke Suzuki <utatane.tea@gmail.com> >+ >+ Add self.queueMicrotask(f) >+ https://bugs.webkit.org/show_bug.cgi?id=188212 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * js/dom/queue-microtask-window-expected.txt: Added. >+ * js/dom/queue-microtask-window.html: Added. >+ * js/dom/queue-microtask-workers-expected.txt: Added. >+ * js/dom/queue-microtask-workers.html: Added. >+ * js/dom/script-tests/queue-microtask-workers.js: Added. >+ (new.Promise): >+ (then.): >+ (then): >+ > 2018-07-31 Ross Kirsling <ross.kirsling@sony.com> > > [WinCairo] Unreviewed test gardening. >diff --git a/LayoutTests/js/dom/queue-microtask-window-expected.txt b/LayoutTests/js/dom/queue-microtask-window-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..cc06f58ccb84fdcf7324071bc04d06d30d3bafad >--- /dev/null >+++ b/LayoutTests/js/dom/queue-microtask-window-expected.txt >@@ -0,0 +1,7 @@ >+ >+ >+PASS Queued microtasks should be drained before executing macrotasks >+PASS queueMicrotask's callback has zero arguments and self as |this| >+PASS queueMicrotask and Promise uses the same Microtask queue >+PASS queueMicrotask should reject non-function arguments >+ >diff --git a/LayoutTests/js/dom/queue-microtask-window.html b/LayoutTests/js/dom/queue-microtask-window.html >new file mode 100644 >index 0000000000000000000000000000000000000000..4b5e4f9453b51e63669957c60c5f1056a02ce8d4 >--- /dev/null >+++ b/LayoutTests/js/dom/queue-microtask-window.html >@@ -0,0 +1,110 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<title>self.queueMicrotask works in Window</title> >+<script src="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+</head> >+<body> >+<iframe></iframe> >+<script> >+promise_test(() => { >+ var counter = 0; >+ self.queueMicrotask(() => { >+ assert_equals(counter++, 1); >+ self.queueMicrotask(() => { >+ assert_equals(counter++, 2); >+ }); >+ }); >+ var promise = new Promise((resolve, reject) => { >+ setTimeout(() => { >+ assert_equals(counter++, 3); >+ resolve(); >+ }, 0); >+ }); >+ assert_equals(counter++, 0); >+ return promise; >+}, `Queued microtasks should be drained before executing macrotasks`); >+ >+promise_test(() => { >+ return new Promise((resolve, reject) => { >+ self.queueMicrotask(function () { >+ try { >+ assert_equals(arguments.length, 0); >+ assert_equals(this, self); >+ assert_equals(frames.length, 1); >+ assert_not_equals(frames[0], self); >+ var iframe = frames[0]; >+ iframe.queueMicrotask(function () { >+ try { >+ assert_equals(this, self); >+ assert_not_equals(this, iframe); >+ self.queueMicrotask(function () { >+ 'use strict'; >+ try { >+ assert_equals(this, undefined); >+ resolve(); >+ } catch (e) { >+ reject(e); >+ } >+ }); >+ } catch (e) { >+ reject(e); >+ } >+ }); >+ } catch (e) { >+ reject(e); >+ } >+ }); >+ }); >+}, `queueMicrotask's callback has zero arguments and self as |this|`); >+ >+promise_test(() => { >+ return new Promise((resolve ,reject) => { >+ var counter = 0; >+ Promise.resolve().then(() => { >+ assert_equals(counter++, 1); >+ self.queueMicrotask(() => { >+ assert_equals(counter++, 3); >+ resolve(); >+ }); >+ }); >+ self.queueMicrotask(() => { >+ assert_equals(counter++, 2); >+ }); >+ assert_equals(counter++, 0); >+ }); >+}, `queueMicrotask and Promise uses the same Microtask queue`); >+ >+test(() => { >+ assert_throws(new TypeError, () => { >+ self.queueMicrotask(); >+ }); >+ assert_throws(new TypeError, () => { >+ self.queueMicrotask(null); >+ }); >+ assert_throws(new TypeError, () => { >+ self.queueMicrotask(undefined); >+ }); >+ assert_throws(new TypeError, () => { >+ self.queueMicrotask(42); >+ }); >+ assert_throws(new TypeError, () => { >+ self.queueMicrotask("42"); >+ }); >+ assert_throws(new TypeError, () => { >+ self.queueMicrotask(true); >+ }); >+ assert_throws(new TypeError, () => { >+ self.queueMicrotask(Symbol("42")); >+ }); >+ assert_throws(new TypeError, () => { >+ self.queueMicrotask({}); >+ }); >+ assert_throws(new TypeError, () => { >+ self.queueMicrotask({ handleEvent() { } }); >+ }); >+}, `queueMicrotask should reject non-function arguments`); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/js/dom/queue-microtask-workers-expected.txt b/LayoutTests/js/dom/queue-microtask-workers-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..07b3cec3b85517d41ed16a6357a435d79fa9412a >--- /dev/null >+++ b/LayoutTests/js/dom/queue-microtask-workers-expected.txt >@@ -0,0 +1,25 @@ >+Starting worker: ./script-tests/queue-microtask-workers.js >+PASS [Worker] counter++ is 0 >+PASS [Worker] counter++ is 1 >+PASS [Worker] counter++ is 2 >+PASS [Worker] counter++ is 3 >+PASS [Worker] argsValue.length is 0 >+PASS [Worker] thisValue is self >+PASS [Worker] thisValue is undefined >+PASS [Worker] counter++ is 0 >+PASS [Worker] counter++ is 1 >+PASS [Worker] counter++ is 2 >+PASS [Worker] counter++ is 3 >+PASS [Worker] self.queueMicrotask() threw exception TypeError: Not enough arguments. >+PASS [Worker] self.queueMicrotask(null) threw exception TypeError: Argument 1 ('callback') to WorkerGlobalScope.queueMicrotask must be a function. >+PASS [Worker] self.queueMicrotask(undefined) threw exception TypeError: Argument 1 ('callback') to WorkerGlobalScope.queueMicrotask must be a function. >+PASS [Worker] self.queueMicrotask(42) threw exception TypeError: Argument 1 ('callback') to WorkerGlobalScope.queueMicrotask must be a function. >+PASS [Worker] self.queueMicrotask("42") threw exception TypeError: Argument 1 ('callback') to WorkerGlobalScope.queueMicrotask must be a function. >+PASS [Worker] self.queueMicrotask(true) threw exception TypeError: Argument 1 ('callback') to WorkerGlobalScope.queueMicrotask must be a function. >+PASS [Worker] self.queueMicrotask(Symbol("42")) threw exception TypeError: Argument 1 ('callback') to WorkerGlobalScope.queueMicrotask must be a function. >+PASS [Worker] self.queueMicrotask({}) threw exception TypeError: Argument 1 ('callback') to WorkerGlobalScope.queueMicrotask must be a function. >+PASS [Worker] self.queueMicrotask({ handleEvent() { } }) threw exception TypeError: Argument 1 ('callback') to WorkerGlobalScope.queueMicrotask must be a function. >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/js/dom/queue-microtask-workers.html b/LayoutTests/js/dom/queue-microtask-workers.html >new file mode 100644 >index 0000000000000000000000000000000000000000..aca280205fdfe8d3214f3b37018845425d67d0db >--- /dev/null >+++ b/LayoutTests/js/dom/queue-microtask-workers.html >@@ -0,0 +1,14 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<div id="description"></div> >+<div id="console"></div> >+<script> >+worker = startWorker('./script-tests/queue-microtask-workers.js'); >+</script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >diff --git a/LayoutTests/js/dom/script-tests/queue-microtask-workers.js b/LayoutTests/js/dom/script-tests/queue-microtask-workers.js >new file mode 100644 >index 0000000000000000000000000000000000000000..1dbbb9fed61211d771c44b4a70e74516fedc17cb >--- /dev/null >+++ b/LayoutTests/js/dom/script-tests/queue-microtask-workers.js >@@ -0,0 +1,71 @@ >+importScripts('../../../resources/js-test-pre.js'); >+ >+var global = this; >+ >+global.jsTestIsAsync = true; >+var reject; >+ >+var counter = 0; >+var argsValue = null; >+var thisValue = null; >+new Promise((resolve, reject) => { >+ self.queueMicrotask(() => { >+ shouldBe(`counter++`, `1`); >+ self.queueMicrotask(() => { >+ shouldBe(`counter++`, `2`); >+ }); >+ }); >+ setTimeout(() => { >+ shouldBe(`counter++`, `3`); >+ resolve(); >+ }, 0); >+ shouldBe(`counter++`, `0`); >+}).then(() => { >+ return new Promise((resolve, reject) => { >+ self.queueMicrotask(function () { >+ try { >+ argsValue = arguments; >+ thisValue = this; >+ shouldBe(`argsValue.length`, `0`); >+ shouldBe(`thisValue`, `self`); >+ self.queueMicrotask(function () { >+ 'use strict'; >+ try { >+ thisValue = this; >+ shouldBe(`thisValue`, `undefined`); >+ resolve(); >+ } catch (e) { >+ reject(e); >+ } >+ }); >+ } catch (e) { >+ reject(e); >+ } >+ }); >+ }); >+}).then(() => { >+ counter = 0; >+ return new Promise((resolve ,reject) => { >+ Promise.resolve().then(() => { >+ shouldBe(`counter++`, `1`); >+ self.queueMicrotask(() => { >+ shouldBe(`counter++`, `3`); >+ resolve(); >+ }); >+ }); >+ self.queueMicrotask(() => { >+ shouldBe(`counter++`, `2`); >+ }); >+ shouldBe(`counter++`, `0`); >+ }); >+}).then(() => { >+ shouldThrow(`self.queueMicrotask()`); >+ shouldThrow(`self.queueMicrotask(null)`); >+ shouldThrow(`self.queueMicrotask(undefined)`); >+ shouldThrow(`self.queueMicrotask(42)`); >+ shouldThrow(`self.queueMicrotask("42")`); >+ shouldThrow(`self.queueMicrotask(true)`); >+ shouldThrow(`self.queueMicrotask(Symbol("42"))`); >+ shouldThrow(`self.queueMicrotask({})`); >+ shouldThrow(`self.queueMicrotask({ handleEvent() { } })`); >+}).then(finishJSTest, finishJSTest);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 188212
:
346275
|
346353
|
346354
|
346355