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;