Title: [289058] trunk
Revision
289058
Author
[email protected]
Date
2022-02-03 09:58:13 -0800 (Thu, 03 Feb 2022)

Log Message

Implement AbortSignal.timeout()
https://bugs.webkit.org/show_bug.cgi?id=236039

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

Import AbortSignal.timeout() tests from upstream WPT.

* web-platform-tests/dom/abort/AbortSignal.any-expected.txt:
* web-platform-tests/dom/abort/AbortSignal.any.js:
(async_test.t.signal.onabort.t.step_func_done):
(async_test.t.string_appeared_here.signal.onabort.t.step_func):
* web-platform-tests/dom/abort/AbortSignal.any.worker-expected.txt:
* web-platform-tests/dom/abort/abort-signal-timeout-expected.txt: Added.
* web-platform-tests/dom/abort/abort-signal-timeout.html: Added.
* web-platform-tests/dom/abort/w3c-import.log:

Source/WebCore:

Implement the new AbortSignal.timeout() as per:
- https://dom.spec.whatwg.org/#dom-abortsignal-timeout

Test: imported/w3c/web-platform-tests/dom/abort/abort-signal-timeout.html

* bindings/js/JSAbortSignalCustom.cpp:
(WebCore::JSAbortSignalOwner::isReachableFromOpaqueRoots):
* dom/AbortSignal.cpp:
(WebCore::AbortSignal::timeout):
(WebCore::AbortSignal::eventListenersDidChange):
* dom/AbortSignal.h:
* dom/AbortSignal.idl:
* page/DOMTimer.cpp:
(WebCore::DOMTimer::DOMTimer):
(WebCore::DOMTimer::install):
(WebCore::DOMTimer::fired):
* page/DOMTimer.h:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (289057 => 289058)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2022-02-03 17:58:13 UTC (rev 289058)
@@ -1,3 +1,21 @@
+2022-02-03  Chris Dumez  <[email protected]>
+
+        Implement AbortSignal.timeout()
+        https://bugs.webkit.org/show_bug.cgi?id=236039
+
+        Reviewed by Darin Adler.
+
+        Import AbortSignal.timeout() tests from upstream WPT.
+
+        * web-platform-tests/dom/abort/AbortSignal.any-expected.txt:
+        * web-platform-tests/dom/abort/AbortSignal.any.js:
+        (async_test.t.signal.onabort.t.step_func_done):
+        (async_test.t.string_appeared_here.signal.onabort.t.step_func):
+        * web-platform-tests/dom/abort/AbortSignal.any.worker-expected.txt:
+        * web-platform-tests/dom/abort/abort-signal-timeout-expected.txt: Added.
+        * web-platform-tests/dom/abort/abort-signal-timeout.html: Added.
+        * web-platform-tests/dom/abort/w3c-import.log:
+
 2022-02-03  Antoine Quint  <[email protected]>
 
         Incorrect KeyframesEffect generated for background

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any-expected.txt (289057 => 289058)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any-expected.txt	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any-expected.txt	2022-02-03 17:58:13 UTC (rev 289058)
@@ -1,4 +1,7 @@
 
 PASS the AbortSignal.abort() static returns an already aborted signal
 PASS signal returned by AbortSignal.abort() should not fire abort event
+PASS AbortSignal.timeout() returns a non-aborted signal
+PASS Signal returned by AbortSignal.timeout() times out
+PASS AbortSignal timeouts fire in order
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any.js (289057 => 289058)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any.js	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any.js	2022-02-03 17:58:13 UTC (rev 289058)
@@ -10,3 +10,31 @@
   s._onabort_ = t.unreached_func("abort event handler called");
   t.step_timeout(() => { t.done(); }, 2000);
 }, "signal returned by AbortSignal.abort() should not fire abort event");
+
+test(t => {
+  const signal = AbortSignal.timeout(0);
+  assert_true(signal instanceof AbortSignal, "returned object is an AbortSignal");
+  assert_false(signal.aborted, "returned signal is not already aborted");
+}, "AbortSignal.timeout() returns a non-aborted signal");
+
+async_test(t => {
+  const signal = AbortSignal.timeout(5);
+  signal._onabort_ = t.step_func_done(() => {
+    assert_true(signal.aborted, "signal is aborted");
+    assert_true(signal.reason instanceof DOMException, "signal.reason is a DOMException");
+    assert_equals(signal.reason.name, "TimeoutError", "signal.reason is a TimeoutError");
+  });
+}, "Signal returned by AbortSignal.timeout() times out");
+
+async_test(t => {
+  let result = "";
+  for (const value of ["1", "2", "3"]) {
+    const signal = AbortSignal.timeout(5);
+    signal._onabort_ = t.step_func(() => { result += value; });
+  }
+
+  const signal = AbortSignal.timeout(5);
+  signal._onabort_ = t.step_func_done(() => {
+    assert_equals(result, "123", "Timeout order should be 123");
+  });
+}, "AbortSignal timeouts fire in order");

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any.worker-expected.txt (289057 => 289058)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any.worker-expected.txt	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any.worker-expected.txt	2022-02-03 17:58:13 UTC (rev 289058)
@@ -1,4 +1,7 @@
 
 PASS the AbortSignal.abort() static returns an already aborted signal
 PASS signal returned by AbortSignal.abort() should not fire abort event
+PASS AbortSignal.timeout() returns a non-aborted signal
+PASS Signal returned by AbortSignal.timeout() times out
+PASS AbortSignal timeouts fire in order
 

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/abort-signal-timeout-expected.txt (0 => 289058)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/abort-signal-timeout-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/abort-signal-timeout-expected.txt	2022-02-03 17:58:13 UTC (rev 289058)
@@ -0,0 +1,3 @@
+
+PASS Signal returned by AbortSignal.timeout() is not aborted after frame detach
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/abort-signal-timeout.html (0 => 289058)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/abort-signal-timeout.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/abort-signal-timeout.html	2022-02-03 17:58:13 UTC (rev 289058)
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>AbortSignal.timeout frame detach</title>
+<script src=""
+<script src=""
+<iframe id="iframe"></iframe>
+<script>
+  async_test(t => {
+    const signal = iframe.contentWindow.AbortSignal.timeout(5);
+    signal._onabort_ = t.unreached_func("abort must not fire");
+
+    iframe.remove();
+
+    t.step_timeout(() => {
+      assert_false(signal.aborted);
+      t.done();
+    }, 10);
+  }, "Signal returned by AbortSignal.timeout() is not aborted after frame detach");
+</script>

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/w3c-import.log (289057 => 289058)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/w3c-import.log	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/abort/w3c-import.log	2022-02-03 17:58:13 UTC (rev 289058)
@@ -15,5 +15,6 @@
 ------------------------------------------------------------------------
 List of files:
 /LayoutTests/imported/w3c/web-platform-tests/dom/abort/AbortSignal.any.js
+/LayoutTests/imported/w3c/web-platform-tests/dom/abort/abort-signal-timeout.html
 /LayoutTests/imported/w3c/web-platform-tests/dom/abort/event.any.js
 /LayoutTests/imported/w3c/web-platform-tests/dom/abort/reason-constructor.html

Modified: trunk/Source/WebCore/ChangeLog (289057 => 289058)


--- trunk/Source/WebCore/ChangeLog	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/Source/WebCore/ChangeLog	2022-02-03 17:58:13 UTC (rev 289058)
@@ -1,3 +1,28 @@
+2022-02-03  Chris Dumez  <[email protected]>
+
+        Implement AbortSignal.timeout()
+        https://bugs.webkit.org/show_bug.cgi?id=236039
+
+        Reviewed by Darin Adler.
+
+        Implement the new AbortSignal.timeout() as per:
+        - https://dom.spec.whatwg.org/#dom-abortsignal-timeout
+
+        Test: imported/w3c/web-platform-tests/dom/abort/abort-signal-timeout.html
+
+        * bindings/js/JSAbortSignalCustom.cpp:
+        (WebCore::JSAbortSignalOwner::isReachableFromOpaqueRoots):
+        * dom/AbortSignal.cpp:
+        (WebCore::AbortSignal::timeout):
+        (WebCore::AbortSignal::eventListenersDidChange):
+        * dom/AbortSignal.h:
+        * dom/AbortSignal.idl:
+        * page/DOMTimer.cpp:
+        (WebCore::DOMTimer::DOMTimer):
+        (WebCore::DOMTimer::install):
+        (WebCore::DOMTimer::fired):
+        * page/DOMTimer.h:
+
 2022-02-03  Mark Lam  <[email protected]>
 
         Flaky scope.assertNoException() assertion in ~JSExecState when running workers WPT tests

Modified: trunk/Source/WebCore/bindings/js/JSAbortSignalCustom.cpp (289057 => 289058)


--- trunk/Source/WebCore/bindings/js/JSAbortSignalCustom.cpp	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/Source/WebCore/bindings/js/JSAbortSignalCustom.cpp	2022-02-03 17:58:13 UTC (rev 289058)
@@ -1,5 +1,5 @@
 /*
-* Copyright (C) 2019-2021 Apple Inc. All rights reserved.
+* Copyright (C) 2019-2022 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -43,6 +43,9 @@
     if (abortSignal.isFollowingSignal())
         return true;
 
+    if (abortSignal.hasAbortEventListener() && abortSignal.hasActiveTimeoutTimer())
+        return true;
+
     return visitor.containsOpaqueRoot(&abortSignal);
 }
 

Modified: trunk/Source/WebCore/dom/AbortSignal.cpp (289057 => 289058)


--- trunk/Source/WebCore/dom/AbortSignal.cpp	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/Source/WebCore/dom/AbortSignal.cpp	2022-02-03 17:58:13 UTC (rev 289058)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
 
 #include "AbortAlgorithm.h"
 #include "DOMException.h"
+#include "DOMTimer.h"
 #include "Event.h"
 #include "EventNames.h"
 #include "JSDOMException.h"
@@ -53,6 +54,26 @@
     return adoptRef(*new AbortSignal(&context, Aborted::Yes, reason));
 }
 
+// https://dom.spec.whatwg.org/#dom-abortsignal-timeout
+Ref<AbortSignal> AbortSignal::timeout(ScriptExecutionContext& context, uint64_t milliseconds)
+{
+    auto signal = adoptRef(*new AbortSignal(&context));
+    signal->setHasActiveTimeoutTimer(true);
+    auto action = "" context) mutable {
+        signal->setHasActiveTimeoutTimer(false);
+
+        auto* globalObject = jsCast<JSDOMGlobalObject*>(context.globalObject());
+        if (!globalObject)
+            return;
+
+        auto& vm = globalObject->vm();
+        Locker locker { vm.apiLock() };
+        signal->signalAbort(toJS(globalObject, globalObject, DOMException::create(TimeoutError)));
+    };
+    DOMTimer::install(context, WTFMove(action), Seconds::fromMilliseconds(milliseconds), true);
+    return signal;
+}
+
 AbortSignal::AbortSignal(ScriptExecutionContext* context, Aborted aborted, JSC::JSValue reason)
     : ContextDestructionObserver(context)
     , m_aborted(aborted == Aborted::Yes)
@@ -61,6 +82,8 @@
     ASSERT(reason);
 }
 
+AbortSignal::~AbortSignal() = default;
+
 // https://dom.spec.whatwg.org/#abortsignal-signal-abort
 void AbortSignal::signalAbort(JSC::JSValue reason)
 {
@@ -102,6 +125,11 @@
     });
 }
 
+void AbortSignal::eventListenersDidChange()
+{
+    m_hasAbortEventListener = hasEventListeners(eventNames().abortEvent);
+}
+
 bool AbortSignal::whenSignalAborted(AbortSignal& signal, Ref<AbortAlgorithm>&& algorithm)
 {
     if (signal.aborted()) {

Modified: trunk/Source/WebCore/dom/AbortSignal.h (289057 => 289058)


--- trunk/Source/WebCore/dom/AbortSignal.h	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/Source/WebCore/dom/AbortSignal.h	2022-02-03 17:58:13 UTC (rev 289058)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -43,8 +43,10 @@
     WTF_MAKE_ISO_ALLOCATED_EXPORT(AbortSignal, WEBCORE_EXPORT);
 public:
     static Ref<AbortSignal> create(ScriptExecutionContext*);
+    WEBCORE_EXPORT ~AbortSignal();
 
     static Ref<AbortSignal> abort(JSDOMGlobalObject&, ScriptExecutionContext&, JSC::JSValue reason);
+    static Ref<AbortSignal> timeout(ScriptExecutionContext&, uint64_t milliseconds);
 
     static bool whenSignalAborted(AbortSignal&, Ref<AbortAlgorithm>&&);
 
@@ -54,6 +56,9 @@
     bool aborted() const { return m_aborted; }
     const JSValueInWrappedObject& reason() const { return m_reason; }
 
+    bool hasActiveTimeoutTimer() const { return m_hasActiveTimeoutTimer; }
+    bool hasAbortEventListener() const { return m_hasAbortEventListener; }
+
     using RefCounted::ref;
     using RefCounted::deref;
 
@@ -68,16 +73,21 @@
     enum class Aborted : bool { No, Yes };
     explicit AbortSignal(ScriptExecutionContext*, Aborted = Aborted::No, JSC::JSValue reason = JSC::jsUndefined());
 
+    void setHasActiveTimeoutTimer(bool hasActiveTimeoutTimer) { m_hasActiveTimeoutTimer = hasActiveTimeoutTimer; }
+
     // EventTarget.
     EventTargetInterface eventTargetInterface() const final { return AbortSignalEventTargetInterfaceType; }
     ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); }
     void refEventTarget() final { ref(); }
     void derefEventTarget() final { deref(); }
+    void eventListenersDidChange() final;
     
     bool m_aborted { false };
     Vector<Algorithm> m_algorithms;
     WeakPtr<AbortSignal> m_followingSignal;
     JSValueInWrappedObject m_reason;
+    bool m_hasActiveTimeoutTimer { false };
+    bool m_hasAbortEventListener { false };
 };
 
 }

Modified: trunk/Source/WebCore/dom/AbortSignal.idl (289057 => 289058)


--- trunk/Source/WebCore/dom/AbortSignal.idl	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/Source/WebCore/dom/AbortSignal.idl	2022-02-03 17:58:13 UTC (rev 289058)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,6 +33,8 @@
     [PrivateIdentifier] static boolean whenSignalAborted(AbortSignal object, AbortAlgorithm algorithm);
 
     [NewObject, CallWith=ScriptExecutionContext&GlobalObject] static AbortSignal abort(optional any reason);
+    [NewObject, CallWith=ScriptExecutionContext] static AbortSignal timeout([EnforceRange] unsigned long long milliseconds);
+
     readonly attribute boolean aborted;
     readonly attribute any reason;
     [CallWith=GlobalObject] undefined throwIfAborted();

Modified: trunk/Source/WebCore/page/DOMTimer.cpp (289057 => 289058)


--- trunk/Source/WebCore/page/DOMTimer.cpp	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/Source/WebCore/page/DOMTimer.cpp	2022-02-03 17:58:13 UTC (rev 289058)
@@ -155,7 +155,7 @@
 
 bool NestedTimersMap::isTrackingNestedTimers = false;
 
-DOMTimer::DOMTimer(ScriptExecutionContext& context, std::unique_ptr<ScheduledAction> action, Seconds interval, bool singleShot)
+DOMTimer::DOMTimer(ScriptExecutionContext& context, Function<void(ScriptExecutionContext&)>&& action, Seconds interval, bool singleShot)
     : SuspendableTimerBase(&context)
     , m_nestingLevel(context.timerNestingLevel())
     , m_action(WTFMove(action))
@@ -174,6 +174,14 @@
 
 int DOMTimer::install(ScriptExecutionContext& context, std::unique_ptr<ScheduledAction> action, Seconds timeout, bool singleShot)
 {
+    auto actionFunction = [action = "" context) mutable {
+        action->execute(context);
+    };
+    return DOMTimer::install(context, WTFMove(actionFunction), timeout, singleShot);
+}
+
+int DOMTimer::install(ScriptExecutionContext& context, Function<void(ScriptExecutionContext&)>&& action, Seconds timeout, bool singleShot)
+{
     Ref<DOMTimer> timer = adoptRef(*new DOMTimer(context, WTFMove(action), timeout, singleShot));
     timer->suspendIfNeeded();
 
@@ -316,7 +324,7 @@
             updateTimerIntervalIfNecessary();
         }
 
-        m_action->execute(context);
+        m_action(context);
 
         InspectorInstrumentation::didFireTimer(context, m_timeoutId, oneShot);
 
@@ -334,7 +342,7 @@
 #if ENABLE(CONTENT_CHANGE_OBSERVER)
     ContentChangeObserver::DOMTimerScope observingScope(dynamicDowncast<Document>(context), *this);
 #endif
-    m_action->execute(context);
+    m_action(context);
 
     InspectorInstrumentation::didFireTimer(context, m_timeoutId, oneShot);
 

Modified: trunk/Source/WebCore/page/DOMTimer.h (289057 => 289058)


--- trunk/Source/WebCore/page/DOMTimer.h	2022-02-03 16:38:40 UTC (rev 289057)
+++ trunk/Source/WebCore/page/DOMTimer.h	2022-02-03 17:58:13 UTC (rev 289058)
@@ -55,6 +55,7 @@
     // Creates a new timer owned by specified ScriptExecutionContext, starts it
     // and returns its Id.
     static int install(ScriptExecutionContext&, std::unique_ptr<ScheduledAction>, Seconds timeout, bool singleShot);
+    static int install(ScriptExecutionContext&, Function<void(ScriptExecutionContext&)>&&, Seconds timeout, bool singleShot);
     static void removeById(ScriptExecutionContext&, int timeoutId);
 
     // Notify that the interval may need updating (e.g. because the minimum interval
@@ -64,7 +65,7 @@
     static void scriptDidInteractWithPlugin(HTMLPlugInElement&);
 
 private:
-    DOMTimer(ScriptExecutionContext&, std::unique_ptr<ScheduledAction>, Seconds interval, bool singleShot);
+    DOMTimer(ScriptExecutionContext&, Function<void(ScriptExecutionContext&)>&&, Seconds interval, bool singleShot);
     friend class Internals;
 
     WEBCORE_EXPORT Seconds intervalClampedToMinimum() const;
@@ -88,7 +89,7 @@
 
     int m_timeoutId;
     int m_nestingLevel;
-    std::unique_ptr<ScheduledAction> m_action;
+    Function<void(ScriptExecutionContext&)> m_action;
     Seconds m_originalInterval;
     TimerThrottleState m_throttleState;
     Seconds m_currentTimerInterval;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to