[WK2] Add SPI to retrieve internal IDs for web notifications
[WebKit-https.git] / Source / WebKit2 / WebProcess / Notifications / WebNotificationManager.cpp
1 /*
2  * Copyright (C) 2011, 2012 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 "WebNotificationManager.h"
28
29 #include "WebPage.h"
30 #include "WebProcess.h"
31
32 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
33 #include "WebNotification.h"
34 #include "WebNotificationManagerProxyMessages.h"
35 #include "WebPageProxyMessages.h"
36 #include <WebCore/Document.h>
37 #include <WebCore/Notification.h>
38 #include <WebCore/Page.h>
39 #include <WebCore/ScriptExecutionContext.h>
40 #include <WebCore/SecurityOrigin.h>
41 #include <WebCore/Settings.h>
42 #endif
43
44 using namespace WebCore;
45
46 namespace WebKit {
47
48 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
49 static uint64_t generateNotificationID()
50 {
51     static uint64_t uniqueNotificationID = 1;
52     return uniqueNotificationID++;
53 }
54 #endif
55
56 WebNotificationManager::WebNotificationManager(WebProcess* process)
57     : m_process(process)
58 {
59 }
60
61 WebNotificationManager::~WebNotificationManager()
62 {
63 }
64
65 void WebNotificationManager::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
66 {
67     didReceiveWebNotificationManagerMessage(connection, messageID, arguments);
68 }
69
70 void WebNotificationManager::initialize(const HashMap<String, bool>& permissions)
71 {
72 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
73     m_permissionsMap = permissions;
74 #endif
75 }
76
77 void WebNotificationManager::didUpdateNotificationDecision(const String& originString, bool allowed)
78 {
79 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
80     m_permissionsMap.set(originString, allowed);
81 #endif
82 }
83
84 void WebNotificationManager::didRemoveNotificationDecisions(const Vector<String>& originStrings)
85 {
86 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
87     size_t count = originStrings.size();
88     for (size_t i = 0; i < count; ++i)
89         m_permissionsMap.remove(originStrings[i]);
90 #endif
91 }
92
93 NotificationClient::Permission WebNotificationManager::policyForOrigin(WebCore::SecurityOrigin *origin) const
94 {
95 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
96     if (!origin)
97         return NotificationClient::PermissionNotAllowed;
98
99     ASSERT(!origin->isUnique());
100     HashMap<String, bool>::const_iterator it = m_permissionsMap.find(origin->toRawString());
101     if (it != m_permissionsMap.end())
102         return it->second ? NotificationClient::PermissionAllowed : NotificationClient::PermissionDenied;
103 #endif
104     
105     return NotificationClient::PermissionNotAllowed;
106 }
107
108 void WebNotificationManager::removeAllPermissionsForTesting()
109 {
110 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
111     m_permissionsMap.clear();
112 #endif
113 }
114
115 uint64_t WebNotificationManager::notificationIDForTesting(Notification* notification)
116 {
117 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
118     if (!notification)
119         return 0;
120     return m_notificationMap.get(notification);
121 #else
122     return 0;
123 #endif
124 }
125
126 bool WebNotificationManager::show(Notification* notification, WebPage* page)
127 {
128 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
129     if (!notification || !page->corePage()->settings()->notificationsEnabled())
130         return false;
131     
132     uint64_t notificationID = generateNotificationID();
133     m_notificationMap.set(notification, notificationID);
134     m_notificationIDMap.set(notificationID, notification);
135     
136     NotificationContextMap::iterator it = m_notificationContextMap.add(notification->scriptExecutionContext(), Vector<uint64_t>()).iterator;
137     it->second.append(notificationID);
138
139 #if ENABLE(NOTIFICATIONS)
140     m_process->connection()->send(Messages::WebPageProxy::ShowNotification(notification->title(), notification->body(), notification->iconURL().string(), notification->tag(), notification->scriptExecutionContext()->securityOrigin()->toString(), notificationID), page->pageID());
141 #else
142     m_process->connection()->send(Messages::WebPageProxy::ShowNotification(notification->title(), notification->body(), notification->iconURL().string(), notification->replaceId(), notification->scriptExecutionContext()->securityOrigin()->toString(), notificationID), page->pageID());
143 #endif
144     return true;
145 #else
146     return false;
147 #endif
148 }
149
150 void WebNotificationManager::cancel(Notification* notification, WebPage* page)
151 {
152 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
153     if (!notification || !page->corePage()->settings()->notificationsEnabled())
154         return;
155     
156     uint64_t notificationID = m_notificationMap.get(notification);
157     if (!notificationID)
158         return;
159     
160     m_process->connection()->send(Messages::WebNotificationManagerProxy::Cancel(notificationID), page->pageID());
161 #endif
162 }
163
164 void WebNotificationManager::clearNotifications(WebCore::ScriptExecutionContext* context, WebPage* page)
165 {
166 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
167     NotificationContextMap::iterator it = m_notificationContextMap.find(context);
168     if (it == m_notificationContextMap.end())
169         return;
170     
171     Vector<uint64_t>& notificationIDs = it->second;
172     m_process->connection()->send(Messages::WebNotificationManagerProxy::ClearNotifications(notificationIDs), page->pageID());
173     size_t count = notificationIDs.size();
174     for (size_t i = 0; i < count; ++i) {
175         RefPtr<Notification> notification = m_notificationIDMap.take(notificationIDs[i]);
176         if (!notification)
177             continue;
178         notification->finalize();
179         m_notificationMap.remove(notification);
180     }
181     
182     m_notificationContextMap.remove(it);
183 #endif
184 }
185
186 void WebNotificationManager::didDestroyNotification(Notification* notification, WebPage* page)
187 {
188 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
189     uint64_t notificationID = m_notificationMap.take(notification);
190     if (!notificationID)
191         return;
192
193     m_notificationIDMap.remove(notificationID);
194     removeNotificationFromContextMap(notificationID, notification);
195     m_process->connection()->send(Messages::WebNotificationManagerProxy::DidDestroyNotification(notificationID), page->pageID());
196 #endif
197 }
198
199 void WebNotificationManager::didShowNotification(uint64_t notificationID)
200 {
201 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
202     if (!isNotificationIDValid(notificationID))
203         return;
204     
205     RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
206     if (!notification)
207         return;
208
209     notification->dispatchShowEvent();
210 #endif
211 }
212
213 void WebNotificationManager::didClickNotification(uint64_t notificationID)
214 {
215 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
216     if (!isNotificationIDValid(notificationID))
217         return;
218
219     RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
220     if (!notification)
221         return;
222
223     notification->dispatchClickEvent();
224 #endif
225 }
226
227 void WebNotificationManager::didCloseNotifications(const Vector<uint64_t>& notificationIDs)
228 {
229 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
230     size_t count = notificationIDs.size();
231     for (size_t i = 0; i < count; ++i) {
232         uint64_t notificationID = notificationIDs[i];
233         if (!isNotificationIDValid(notificationID))
234             continue;
235
236         RefPtr<Notification> notification = m_notificationIDMap.take(notificationID);
237         if (!notification)
238             continue;
239
240         m_notificationMap.remove(notification);
241         removeNotificationFromContextMap(notificationID, notification.get());
242
243         notification->dispatchCloseEvent();
244     }
245 #endif
246 }
247
248 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
249 void WebNotificationManager::removeNotificationFromContextMap(uint64_t notificationID, Notification* notification)
250 {
251     // This is a helper function for managing the hash maps.
252     NotificationContextMap::iterator it = m_notificationContextMap.find(notification->scriptExecutionContext());
253     ASSERT(it != m_notificationContextMap.end());
254     size_t index = it->second.find(notificationID);
255     ASSERT(index != notFound);
256     it->second.remove(index);
257     if (it->second.isEmpty())
258         m_notificationContextMap.remove(it);
259 }
260 #endif
261
262 } // namespace WebKit