[iOS] Upstream PLATFORM(IOS) changes to Source/WebKit/
[WebKit-https.git] / Source / WebKit / mac / WebCoreSupport / WebNotificationClient.mm
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 #import "WebNotificationClient.h"
27
28 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
29 #import "WebDelegateImplementationCaching.h"
30 #import "WebNotificationInternal.h"
31 #import "WebPreferencesPrivate.h"
32 #import "WebSecurityOriginInternal.h"
33 #import "WebUIDelegatePrivate.h"
34 #import "WebViewInternal.h"
35 #import <WebCore/BlockExceptions.h>
36 #import <WebCore/Page.h>
37 #import <WebCore/ScriptExecutionContext.h>
38 #endif
39
40 #if ENABLE(NOTIFICATIONS)
41 #import <WebCore/NotificationPermissionCallback.h>
42 #endif
43 #if ENABLE(LEGACY_NOTIFICATIONS)
44 #import <WebCore/VoidCallback.h>
45 #endif
46
47 using namespace WebCore;
48
49 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
50 @interface WebNotificationPolicyListener : NSObject <WebAllowDenyPolicyListener>
51 {
52 #if ENABLE(NOTIFICATIONS)
53     RefPtr<NotificationPermissionCallback> _callback;
54 #endif
55 #if ENABLE(LEGACY_NOTIFICATIONS)
56     RefPtr<VoidCallback> _voidCallback;
57     bool _isLegacyRequest;
58 #endif
59 }
60 #if ENABLE(NOTIFICATIONS)
61 - (id)initWithCallback:(PassRefPtr<NotificationPermissionCallback>)callback;
62 #endif
63 #if ENABLE(LEGACY_NOTIFICATIONS)
64 - (id)initWithVoidCallback:(PassRefPtr<VoidCallback>)callback;
65 #endif
66
67 @end
68 #endif
69
70 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
71 static uint64_t generateNotificationID()
72 {
73     static uint64_t uniqueNotificationID = 1;
74     return uniqueNotificationID++;
75 }
76 #endif
77
78 WebNotificationClient::WebNotificationClient(WebView *webView)
79     : m_webView(webView)
80 {
81 }
82
83 bool WebNotificationClient::show(Notification* notification)
84 {
85 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
86     if (![m_webView _notificationProvider])
87         return false;
88
89     uint64_t notificationID = generateNotificationID();
90     RetainPtr<WebNotification> webNotification = adoptNS([[WebNotification alloc] initWithCoreNotification:notification notificationID:notificationID]);
91     m_notificationMap.set(notification, webNotification);
92
93     NotificationContextMap::iterator it = m_notificationContextMap.add(notification->scriptExecutionContext(), Vector<RetainPtr<WebNotification>>()).iterator;
94     it->value.append(webNotification);
95
96     [[m_webView _notificationProvider] showNotification:webNotification.get() fromWebView:m_webView];
97     return true;
98 #else
99     UNUSED_PARAM(notification);
100     return false;
101 #endif
102 }
103
104 void WebNotificationClient::cancel(Notification* notification)
105 {
106 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
107     WebNotification *webNotification = m_notificationMap.get(notification).get();
108     if (!webNotification)
109         return;
110
111     [[m_webView _notificationProvider] cancelNotification:webNotification];
112 #else
113     UNUSED_PARAM(notification);
114 #endif
115 }
116
117 void WebNotificationClient::clearNotifications(ScriptExecutionContext* context)
118 {
119 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
120     NotificationContextMap::iterator it = m_notificationContextMap.find(context);
121     if (it == m_notificationContextMap.end())
122         return;
123     
124     Vector<RetainPtr<WebNotification>>& webNotifications = it->value;
125     NSMutableArray *nsIDs = [NSMutableArray array];
126     size_t count = webNotifications.size();
127     for (size_t i = 0; i < count; ++i) {
128         WebNotification *webNotification = webNotifications[i].get();
129         [nsIDs addObject:[NSNumber numberWithUnsignedLongLong:[webNotification notificationID]]];
130         core(webNotification)->finalize();
131         m_notificationMap.remove(core(webNotification));
132     }
133
134     [[m_webView _notificationProvider] clearNotifications:nsIDs];
135     m_notificationContextMap.remove(it);
136 #else
137     UNUSED_PARAM(context);
138 #endif
139 }
140
141 void WebNotificationClient::notificationObjectDestroyed(Notification* notification)
142 {
143 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
144     RetainPtr<WebNotification> webNotification = m_notificationMap.take(notification);
145     if (!webNotification)
146         return;
147
148     NotificationContextMap::iterator it = m_notificationContextMap.find(notification->scriptExecutionContext());
149     ASSERT(it != m_notificationContextMap.end());
150     size_t index = it->value.find(webNotification);
151     ASSERT(index != notFound);
152     it->value.remove(index);
153     if (it->value.isEmpty())
154         m_notificationContextMap.remove(it);
155
156     [[m_webView _notificationProvider] notificationDestroyed:webNotification.get()];
157 #else
158     UNUSED_PARAM(notification);
159 #endif
160 }
161
162 void WebNotificationClient::notificationControllerDestroyed()
163 {
164     delete this;
165 }
166
167 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
168 void WebNotificationClient::requestPermission(ScriptExecutionContext* context, WebNotificationPolicyListener *listener)
169 {
170     SEL selector = @selector(webView:decidePolicyForNotificationRequestFromOrigin:listener:);
171     if (![[m_webView UIDelegate] respondsToSelector:selector])
172         return;
173     
174     WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:context->securityOrigin()];
175     
176     CallUIDelegate(m_webView, selector, webOrigin, listener);
177     
178     [webOrigin release];
179 }
180 #endif
181
182 #if ENABLE(LEGACY_NOTIFICATIONS)
183 void WebNotificationClient::requestPermission(ScriptExecutionContext* context, PassRefPtr<VoidCallback> callback)
184 {
185     BEGIN_BLOCK_OBJC_EXCEPTIONS;
186     WebNotificationPolicyListener *listener = [[WebNotificationPolicyListener alloc] initWithVoidCallback:callback];
187     requestPermission(context, listener);
188     [listener release];
189     END_BLOCK_OBJC_EXCEPTIONS;
190 }
191 #endif
192
193 #if ENABLE(NOTIFICATIONS)
194 void WebNotificationClient::requestPermission(ScriptExecutionContext* context, PassRefPtr<NotificationPermissionCallback> callback)
195 {
196     BEGIN_BLOCK_OBJC_EXCEPTIONS;
197     WebNotificationPolicyListener *listener = [[WebNotificationPolicyListener alloc] initWithCallback:callback];
198     requestPermission(context, listener);
199     [listener release];
200     END_BLOCK_OBJC_EXCEPTIONS;
201 }
202 #endif
203
204 NotificationClient::Permission WebNotificationClient::checkPermission(ScriptExecutionContext* context)
205 {
206 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
207     if (!context || !context->isDocument())
208         return NotificationClient::PermissionDenied;
209     if (![[m_webView preferences] notificationsEnabled])
210         return NotificationClient::PermissionDenied;
211     WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:context->securityOrigin()];
212     WebNotificationPermission permission = [[m_webView _notificationProvider] policyForOrigin:webOrigin];
213     [webOrigin release];
214     switch (permission) {
215         case WebNotificationPermissionAllowed:
216             return NotificationClient::PermissionAllowed;
217         case WebNotificationPermissionDenied:
218             return NotificationClient::PermissionDenied;
219         case WebNotificationPermissionNotAllowed:
220             return NotificationClient::PermissionNotAllowed;
221         default:
222             return NotificationClient::PermissionNotAllowed;
223     }
224 #else
225     UNUSED_PARAM(context);
226     return NotificationClient::PermissionDenied;
227 #endif
228 }
229
230 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
231 uint64_t WebNotificationClient::notificationIDForTesting(WebCore::Notification* notification)
232 {
233     return [m_notificationMap.get(notification).get() notificationID];
234 }
235
236 @implementation WebNotificationPolicyListener
237
238 #if ENABLE(NOTIFICATIONS)
239 - (id)initWithCallback:(PassRefPtr<NotificationPermissionCallback>)callback
240 {
241     if (!(self = [super init]))
242         return nil;
243
244     _callback = callback;
245     return self;
246 }
247 #endif
248
249 #if ENABLE(LEGACY_NOTIFICATIONS)
250 - (id)initWithVoidCallback:(PassRefPtr<VoidCallback>)callback
251 {
252     if (!(self = [super init]))
253         return nil;
254
255     _isLegacyRequest = true;
256     _voidCallback = callback;
257     return self;
258 }
259 #endif
260
261 - (void)allow
262 {
263 #if ENABLE(LEGACY_NOTIFICATIONS)
264     if (_isLegacyRequest) {
265         if (_voidCallback)
266             _voidCallback->handleEvent();
267         return;
268     }
269 #endif
270 #if ENABLE(NOTIFICATIONS)
271     if (_callback)
272         _callback->handleEvent(Notification::permissionString(NotificationClient::PermissionAllowed));
273 #endif
274 }
275
276 - (void)deny
277 {
278 #if ENABLE(LEGACY_NOTIFICATIONS)
279     if (_isLegacyRequest) {
280         if (_voidCallback)
281             _voidCallback->handleEvent();
282         return;
283     }
284 #endif
285 #if ENABLE(NOTIFICATIONS)
286     if (_callback)
287         _callback->handleEvent(Notification::permissionString(NotificationClient::PermissionDenied));
288 #endif
289 }
290
291 #if PLATFORM(IOS)
292 - (void)denyOnlyThisRequest
293 {
294     ASSERT_NOT_REACHED();
295 }
296
297 - (BOOL)shouldClearCache
298 {
299     ASSERT_NOT_REACHED();
300     return NO;
301 }
302 #endif
303
304 @end
305 #endif