Remove support for legacy Notifications
[WebKit-https.git] / Source / WebCore / Modules / notifications / Notification.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  * Copyright (C) 2009, 2011, 2012, 2016 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33
34 #if ENABLE(NOTIFICATIONS)
35
36 #include "Notification.h"
37
38 #include "Document.h"
39 #include "Event.h"
40 #include "EventNames.h"
41 #include "ExceptionCode.h"
42 #include "NotificationController.h"
43 #include "NotificationPermissionCallback.h"
44 #include "WindowFocusAllowedIndicator.h"
45
46 namespace WebCore {
47
48 Notification::Notification(Document& document, const String& title)
49     : ActiveDOMObject(&document)
50     , m_title(title)
51     , m_state(Idle)
52     , m_taskTimer(std::make_unique<Timer>([this] () { show(); }))
53 {
54     m_taskTimer->startOneShot(0_s);
55 }
56
57 Notification::~Notification() 
58 {
59 }
60
61 static String directionString(Notification::Direction direction)
62 {
63     // FIXME: Storing this as a string is not the right way to do it.
64     // FIXME: Seems highly unlikely that this does the right thing for Auto.
65     switch (direction) {
66     case Notification::Direction::Auto:
67         return ASCIILiteral("auto");
68     case Notification::Direction::Ltr:
69         return ASCIILiteral("ltr");
70     case Notification::Direction::Rtl:
71         return ASCIILiteral("rtl");
72     }
73     ASSERT_NOT_REACHED();
74     return { };
75 }
76
77 Ref<Notification> Notification::create(Document& context, const String& title, const Options& options)
78 {
79     auto notification = adoptRef(*new Notification(context, title));
80     notification->m_body = options.body;
81     notification->m_tag = options.tag;
82     notification->m_lang = options.lang;
83     notification->m_direction = directionString(options.dir);
84     if (!options.icon.isEmpty()) {
85         auto iconURL = context.completeURL(options.icon);
86         if (iconURL.isValid())
87             notification->m_icon = iconURL;
88     }
89     notification->suspendIfNeeded();
90     return notification;
91 }
92
93 void Notification::show() 
94 {
95     // prevent double-showing
96     if (m_state != Idle)
97         return;
98
99     auto* page = downcast<Document>(*scriptExecutionContext()).page();
100     if (!page)
101         return;
102
103     auto& client = NotificationController::from(page)->client();
104
105     if (client.checkPermission(scriptExecutionContext()) != NotificationClient::PermissionAllowed) {
106         dispatchErrorEvent();
107         return;
108     }
109     if (client.show(this)) {
110         m_state = Showing;
111         setPendingActivity(this);
112     }
113 }
114
115 void Notification::close()
116 {
117     switch (m_state) {
118     case Idle:
119         break;
120     case Showing: {
121         auto* page = downcast<Document>(*scriptExecutionContext()).page();
122         if (page)
123             NotificationController::from(page)->client().cancel(this);
124         break;
125     }
126     case Closed:
127         break;
128     }
129 }
130
131 void Notification::contextDestroyed()
132 {
133     ActiveDOMObject::contextDestroyed();
134
135     auto* page = downcast<Document>(*scriptExecutionContext()).page();
136     if (page)
137         NotificationController::from(page)->client().notificationObjectDestroyed(this);
138 }
139
140 const char* Notification::activeDOMObjectName() const
141 {
142     return "Notification";
143 }
144
145 bool Notification::canSuspendForDocumentSuspension() const
146 {
147     // We can suspend if the Notification is not shown yet or after it is closed.
148     return m_state == Idle || m_state == Closed;
149 }
150
151 void Notification::finalize()
152 {
153     if (m_state == Closed)
154         return;
155     m_state = Closed;
156     unsetPendingActivity(this);
157 }
158
159 void Notification::dispatchShowEvent()
160 {
161     dispatchEvent(Event::create(eventNames().showEvent, false, false));
162 }
163
164 void Notification::dispatchClickEvent()
165 {
166     WindowFocusAllowedIndicator windowFocusAllowed;
167     dispatchEvent(Event::create(eventNames().clickEvent, false, false));
168 }
169
170 void Notification::dispatchCloseEvent()
171 {
172     dispatchEvent(Event::create(eventNames().closeEvent, false, false));
173     finalize();
174 }
175
176 void Notification::dispatchErrorEvent()
177 {
178     dispatchEvent(Event::create(eventNames().errorEvent, false, false));
179 }
180
181 String Notification::permission(Document& document)
182 {
183     return permissionString(NotificationController::from(document.page())->client().checkPermission(&document));
184 }
185
186 String Notification::permissionString(NotificationClient::Permission permission)
187 {
188     switch (permission) {
189     case NotificationClient::PermissionAllowed:
190         return ASCIILiteral("granted");
191     case NotificationClient::PermissionDenied:
192         return ASCIILiteral("denied");
193     case NotificationClient::PermissionNotAllowed:
194         return ASCIILiteral("default");
195     }
196     ASSERT_NOT_REACHED();
197     return { };
198 }
199
200 void Notification::requestPermission(Document& document, RefPtr<NotificationPermissionCallback>&& callback)
201 {
202     NotificationController::from(document.page())->client().requestPermission(&document, WTFMove(callback));
203 }
204
205 } // namespace WebCore
206
207 #endif // ENABLE(NOTIFICATIONS)