1/* 2 * Copyright (C) 2011, 2013 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 "WebNotificationManagerProxy.h" 28 29#include "ImmutableArray.h" 30#include "ImmutableDictionary.h" 31#include "WebContext.h" 32#include "WebNotification.h" 33#include "WebNotificationManagerMessages.h" 34#include "WebPageProxy.h" 35#include "WebProcessProxy.h" 36#include "WebSecurityOrigin.h" 37 38using namespace std; 39using namespace WTF; 40using namespace WebCore; 41 42namespace WebKit { 43 44static uint64_t generateGlobalNotificationID() 45{ 46 static uint64_t uniqueGlobalNotificationID = 1; 47 return uniqueGlobalNotificationID++; 48} 49 50const char* WebNotificationManagerProxy::supplementName() 51{ 52 return "WebNotificationManagerProxy"; 53} 54 55PassRefPtr<WebNotificationManagerProxy> WebNotificationManagerProxy::create(WebContext* context) 56{ 57 return adoptRef(new WebNotificationManagerProxy(context)); 58} 59 60WebNotificationManagerProxy::WebNotificationManagerProxy(WebContext* context) 61 : WebContextSupplement(context) 62{ 63} 64 65void WebNotificationManagerProxy::initializeProvider(const WKNotificationProvider *provider) 66{ 67 m_provider.initialize(provider); 68 m_provider.addNotificationManager(this); 69} 70 71// WebContextSupplement 72 73void WebNotificationManagerProxy::contextDestroyed() 74{ 75 m_provider.removeNotificationManager(this); 76} 77 78void WebNotificationManagerProxy::refWebContextSupplement() 79{ 80 APIObject::ref(); 81} 82 83void WebNotificationManagerProxy::derefWebContextSupplement() 84{ 85 APIObject::deref(); 86} 87 88void WebNotificationManagerProxy::populateCopyOfNotificationPermissions(HashMap<String, bool>& permissions) 89{ 90 RefPtr<ImmutableDictionary> knownPermissions = m_provider.notificationPermissions(); 91 92 if (!knownPermissions) 93 return; 94 95 permissions.clear(); 96 RefPtr<ImmutableArray> knownOrigins = knownPermissions->keys(); 97 for (size_t i = 0; i < knownOrigins->size(); ++i) { 98 WebString* origin = knownOrigins->at<WebString>(i); 99 permissions.set(origin->string(), knownPermissions->get<WebBoolean>(origin->string())->value()); 100 } 101} 102 103void WebNotificationManagerProxy::show(WebPageProxy* webPage, const String& title, const String& body, const String& iconURL, const String& tag, const String& lang, const String& dir, const String& originString, uint64_t pageNotificationID) 104{ 105 uint64_t globalNotificationID = generateGlobalNotificationID(); 106 RefPtr<WebNotification> notification = WebNotification::create(title, body, iconURL, tag, lang, dir, originString, globalNotificationID); 107 pair<uint64_t, uint64_t> notificationIDPair = make_pair(webPage->pageID(), pageNotificationID); 108 m_globalNotificationMap.set(globalNotificationID, notificationIDPair); 109 m_notifications.set(notificationIDPair, make_pair(globalNotificationID, notification)); 110 m_provider.show(webPage, notification.get()); 111} 112 113void WebNotificationManagerProxy::cancel(WebPageProxy* webPage, uint64_t pageNotificationID) 114{ 115 if (WebNotification* notification = m_notifications.get(make_pair(webPage->pageID(), pageNotificationID)).second.get()) 116 m_provider.cancel(notification); 117} 118 119void WebNotificationManagerProxy::didDestroyNotification(WebPageProxy* webPage, uint64_t pageNotificationID) 120{ 121 auto globalIDNotificationPair = m_notifications.take(make_pair(webPage->pageID(), pageNotificationID)); 122 if (uint64_t globalNotificationID = globalIDNotificationPair.first) { 123 WebNotification* notification = globalIDNotificationPair.second.get(); 124 m_globalNotificationMap.remove(globalNotificationID); 125 m_provider.didDestroyNotification(notification); 126 } 127} 128 129static bool pageIDsMatch(uint64_t pageID, uint64_t, uint64_t desiredPageID, const Vector<uint64_t>&) 130{ 131 return pageID == desiredPageID; 132} 133 134static bool pageAndNotificationIDsMatch(uint64_t pageID, uint64_t pageNotificationID, uint64_t desiredPageID, const Vector<uint64_t>& desiredPageNotificationIDs) 135{ 136 return pageID == desiredPageID && desiredPageNotificationIDs.contains(pageNotificationID); 137} 138 139void WebNotificationManagerProxy::clearNotifications(WebPageProxy* webPage) 140{ 141 clearNotifications(webPage, Vector<uint64_t>(), pageIDsMatch); 142} 143 144void WebNotificationManagerProxy::clearNotifications(WebPageProxy* webPage, const Vector<uint64_t>& pageNotificationIDs) 145{ 146 clearNotifications(webPage, pageNotificationIDs, pageAndNotificationIDsMatch); 147} 148 149void WebNotificationManagerProxy::clearNotifications(WebPageProxy* webPage, const Vector<uint64_t>& pageNotificationIDs, NotificationFilterFunction filterFunction) 150{ 151 uint64_t targetPageID = webPage->pageID(); 152 153 Vector<uint64_t> globalNotificationIDs; 154 globalNotificationIDs.reserveCapacity(m_globalNotificationMap.size()); 155 156 for (auto it = m_notifications.begin(), end = m_notifications.end(); it != end; ++it) { 157 uint64_t webPageID = it->key.first; 158 uint64_t pageNotificationID = it->key.second; 159 if (!filterFunction(webPageID, pageNotificationID, targetPageID, pageNotificationIDs)) 160 continue; 161 162 uint64_t globalNotificationID = it->value.first; 163 globalNotificationIDs.append(globalNotificationID); 164 } 165 166 for (auto it = globalNotificationIDs.begin(), end = globalNotificationIDs.end(); it != end; ++it) { 167 auto pageNotification = m_globalNotificationMap.take(*it); 168 m_notifications.remove(pageNotification); 169 } 170 171 m_provider.clearNotifications(globalNotificationIDs); 172} 173 174void WebNotificationManagerProxy::providerDidShowNotification(uint64_t globalNotificationID) 175{ 176 auto it = m_globalNotificationMap.find(globalNotificationID); 177 if (it == m_globalNotificationMap.end()) 178 return; 179 180 uint64_t webPageID = it->value.first; 181 WebPageProxy* webPage = WebProcessProxy::webPage(webPageID); 182 if (!webPage) 183 return; 184 185 uint64_t pageNotificationID = it->value.second; 186 webPage->process()->send(Messages::WebNotificationManager::DidShowNotification(pageNotificationID), 0); 187} 188 189void WebNotificationManagerProxy::providerDidClickNotification(uint64_t globalNotificationID) 190{ 191 auto it = m_globalNotificationMap.find(globalNotificationID); 192 if (it == m_globalNotificationMap.end()) 193 return; 194 195 uint64_t webPageID = it->value.first; 196 WebPageProxy* webPage = WebProcessProxy::webPage(webPageID); 197 if (!webPage) 198 return; 199 200 uint64_t pageNotificationID = it->value.second; 201 webPage->process()->send(Messages::WebNotificationManager::DidClickNotification(pageNotificationID), 0); 202} 203 204 205void WebNotificationManagerProxy::providerDidCloseNotifications(ImmutableArray* globalNotificationIDs) 206{ 207 HashMap<WebPageProxy*, Vector<uint64_t>> pageNotificationIDs; 208 209 size_t size = globalNotificationIDs->size(); 210 for (size_t i = 0; i < size; ++i) { 211 auto it = m_globalNotificationMap.find(globalNotificationIDs->at<WebUInt64>(i)->value()); 212 if (it == m_globalNotificationMap.end()) 213 continue; 214 215 if (WebPageProxy* webPage = WebProcessProxy::webPage(it->value.first)) { 216 auto pageIt = pageNotificationIDs.find(webPage); 217 if (pageIt == pageNotificationIDs.end()) { 218 Vector<uint64_t> newVector; 219 newVector.reserveInitialCapacity(size); 220 pageIt = pageNotificationIDs.add(webPage, newVector).iterator; 221 } 222 223 uint64_t pageNotificationID = it->value.second; 224 pageIt->value.append(pageNotificationID); 225 } 226 227 m_notifications.remove(it->value); 228 m_globalNotificationMap.remove(it); 229 } 230 231 for (auto it = pageNotificationIDs.begin(), end = pageNotificationIDs.end(); it != end; ++it) 232 it->key->process()->send(Messages::WebNotificationManager::DidCloseNotifications(it->value), 0); 233} 234 235void WebNotificationManagerProxy::providerDidUpdateNotificationPolicy(const WebSecurityOrigin* origin, bool allowed) 236{ 237 if (!context()) 238 return; 239 240 context()->sendToAllProcesses(Messages::WebNotificationManager::DidUpdateNotificationDecision(origin->toString(), allowed)); 241} 242 243void WebNotificationManagerProxy::providerDidRemoveNotificationPolicies(ImmutableArray* origins) 244{ 245 if (!context()) 246 return; 247 248 size_t size = origins->size(); 249 if (!size) 250 return; 251 252 Vector<String> originStrings; 253 originStrings.reserveInitialCapacity(size); 254 255 for (size_t i = 0; i < size; ++i) 256 originStrings.append(origins->at<WebSecurityOrigin>(i)->toString()); 257 258 context()->sendToAllProcesses(Messages::WebNotificationManager::DidRemoveNotificationDecisions(originStrings)); 259} 260 261} // namespace WebKit 262