Make all ScriptWrappable IsoHeap-ed
[WebKit-https.git] / Source / WebCore / workers / service / ExtendableEvent.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "ExtendableEvent.h"
28
29 #if ENABLE(SERVICE_WORKER)
30
31 #include "JSDOMPromise.h"
32 #include "ScriptExecutionContext.h"
33 #include <JavaScriptCore/Microtask.h>
34 #include <wtf/IsoMallocInlines.h>
35
36 namespace WebCore {
37
38 WTF_MAKE_ISO_ALLOCATED_IMPL(ExtendableEvent);
39
40 ExtendableEvent::ExtendableEvent(const AtomString& type, const ExtendableEventInit& initializer, IsTrusted isTrusted)
41     : Event(type, initializer, isTrusted)
42 {
43 }
44
45 ExtendableEvent::ExtendableEvent(const AtomString& type, CanBubble canBubble, IsCancelable cancelable)
46     : Event(type, canBubble, cancelable)
47 {
48 }
49
50 ExtendableEvent::~ExtendableEvent()
51 {
52 }
53
54 // https://w3c.github.io/ServiceWorker/#dom-extendableevent-waituntil
55 ExceptionOr<void> ExtendableEvent::waitUntil(Ref<DOMPromise>&& promise)
56 {
57     if (!isTrusted())
58         return Exception { InvalidStateError, "Event is not trusted"_s };
59
60     // If the pending promises count is zero and the dispatch flag is unset, throw an "InvalidStateError" DOMException.
61     if (!m_pendingPromiseCount && !isBeingDispatched())
62         return Exception { InvalidStateError, "Event is no longer being dispatched and has no pending promises"_s };
63
64     addExtendLifetimePromise(WTFMove(promise));
65     return { };
66 }
67
68 class FunctionMicrotask final : public JSC::Microtask {
69 public:
70     static Ref<FunctionMicrotask> create(Function<void()>&& function)
71     {
72         return adoptRef(*new FunctionMicrotask(WTFMove(function)));
73     }
74
75 private:
76     explicit FunctionMicrotask(Function<void()>&& function)
77         : m_function(WTFMove(function))
78     {
79     }
80
81     void run(JSC::ExecState*) final
82     {
83         m_function();
84     }
85
86     Function<void()> m_function;
87 };
88
89 void ExtendableEvent::addExtendLifetimePromise(Ref<DOMPromise>&& promise)
90 {
91     promise->whenSettled([this, protectedThis = makeRefPtr(this), settledPromise = promise.ptr()] () mutable {
92         auto& globalObject = *settledPromise->globalObject();
93         globalObject.queueMicrotask(FunctionMicrotask::create([this, protectedThis = WTFMove(protectedThis), settledPromise = WTFMove(settledPromise)] () mutable {
94             --m_pendingPromiseCount;
95
96             // FIXME: Let registration be the context object's relevant global object's associated service worker's containing service worker registration.
97             // FIXME: If registration's uninstalling flag is set, invoke Try Clear Registration with registration.
98             // FIXME: If registration is not null, invoke Try Activate with registration.
99
100             auto* context = settledPromise->globalObject()->scriptExecutionContext();
101             if (!context)
102                 return;
103             context->postTask([this, protectedThis = WTFMove(protectedThis)] (ScriptExecutionContext&) mutable {
104                 if (m_pendingPromiseCount)
105                     return;
106
107                 auto settledPromises = WTFMove(m_extendLifetimePromises);
108                 if (auto handler = WTFMove(m_whenAllExtendLifetimePromisesAreSettledHandler))
109                     handler(WTFMove(settledPromises));
110             });
111         }));
112     });
113
114     m_extendLifetimePromises.add(WTFMove(promise));
115     ++m_pendingPromiseCount;
116 }
117
118 void ExtendableEvent::whenAllExtendLifetimePromisesAreSettled(WTF::Function<void(HashSet<Ref<DOMPromise>>&&)>&& handler)
119 {
120     ASSERT_WITH_MESSAGE(target(), "Event has not been dispatched yet");
121     ASSERT(!m_whenAllExtendLifetimePromisesAreSettledHandler);
122
123     if (!m_pendingPromiseCount) {
124         handler(WTFMove(m_extendLifetimePromises));
125         return;
126     }
127
128     m_whenAllExtendLifetimePromisesAreSettledHandler = WTFMove(handler);
129 }
130
131 } // namespace WebCore
132
133 #endif // ENABLE(SERVICE_WORKER)