blob: fae1f3fca888719be7f6272d205720bb890177fe [file] [log] [blame]
/*
* Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WebNotificationManagerProxy.h"
#include "APIArray.h"
#include "APINotificationProvider.h"
#include "APISecurityOrigin.h"
#include "WebNotification.h"
#include "WebNotificationManagerMessages.h"
#include "WebPageProxy.h"
#include "WebProcessPool.h"
#include "WebProcessProxy.h"
namespace WebKit {
using namespace WebCore;
static uint64_t generateGlobalNotificationID()
{
static uint64_t uniqueGlobalNotificationID = 1;
return uniqueGlobalNotificationID++;
}
const char* WebNotificationManagerProxy::supplementName()
{
return "WebNotificationManagerProxy";
}
Ref<WebNotificationManagerProxy> WebNotificationManagerProxy::create(WebProcessPool* processPool)
{
return adoptRef(*new WebNotificationManagerProxy(processPool));
}
WebNotificationManagerProxy::WebNotificationManagerProxy(WebProcessPool* processPool)
: WebContextSupplement(processPool)
, m_provider(std::make_unique<API::NotificationProvider>())
{
}
void WebNotificationManagerProxy::setProvider(std::unique_ptr<API::NotificationProvider>&& provider)
{
if (!provider) {
m_provider = std::make_unique<API::NotificationProvider>();
return;
}
m_provider = WTFMove(provider);
m_provider->addNotificationManager(*this);
}
// WebContextSupplement
void WebNotificationManagerProxy::processPoolDestroyed()
{
m_provider->removeNotificationManager(*this);
}
void WebNotificationManagerProxy::refWebContextSupplement()
{
API::Object::ref();
}
void WebNotificationManagerProxy::derefWebContextSupplement()
{
API::Object::deref();
}
HashMap<String, bool> WebNotificationManagerProxy::notificationPermissions()
{
return m_provider->notificationPermissions();
}
void WebNotificationManagerProxy::show(WebPageProxy* webPage, const String& title, const String& body, const String& iconURL, const String& tag, const String& lang, WebCore::NotificationDirection dir, const String& originString, uint64_t pageNotificationID)
{
uint64_t globalNotificationID = generateGlobalNotificationID();
auto notification = WebNotification::create(title, body, iconURL, tag, lang, dir, originString, globalNotificationID);
std::pair<uint64_t, uint64_t> notificationIDPair = std::make_pair(webPage->pageID(), pageNotificationID);
m_globalNotificationMap.set(globalNotificationID, notificationIDPair);
m_notifications.set(notificationIDPair, std::make_pair(globalNotificationID, notification.copyRef()));
m_provider->show(*webPage, notification.get());
}
void WebNotificationManagerProxy::cancel(WebPageProxy* webPage, uint64_t pageNotificationID)
{
if (WebNotification* notification = m_notifications.get(std::make_pair(webPage->pageID(), pageNotificationID)).second.get())
m_provider->cancel(*notification);
}
void WebNotificationManagerProxy::didDestroyNotification(WebPageProxy* webPage, uint64_t pageNotificationID)
{
auto globalIDNotificationPair = m_notifications.take(std::make_pair(webPage->pageID(), pageNotificationID));
if (uint64_t globalNotificationID = globalIDNotificationPair.first) {
WebNotification* notification = globalIDNotificationPair.second.get();
m_globalNotificationMap.remove(globalNotificationID);
m_provider->didDestroyNotification(*notification);
}
}
static bool pageIDsMatch(uint64_t pageID, uint64_t, uint64_t desiredPageID, const Vector<uint64_t>&)
{
return pageID == desiredPageID;
}
static bool pageAndNotificationIDsMatch(uint64_t pageID, uint64_t pageNotificationID, uint64_t desiredPageID, const Vector<uint64_t>& desiredPageNotificationIDs)
{
return pageID == desiredPageID && desiredPageNotificationIDs.contains(pageNotificationID);
}
void WebNotificationManagerProxy::clearNotifications(WebPageProxy* webPage)
{
clearNotifications(webPage, Vector<uint64_t>(), pageIDsMatch);
}
void WebNotificationManagerProxy::clearNotifications(WebPageProxy* webPage, const Vector<uint64_t>& pageNotificationIDs)
{
clearNotifications(webPage, pageNotificationIDs, pageAndNotificationIDsMatch);
}
void WebNotificationManagerProxy::clearNotifications(WebPageProxy* webPage, const Vector<uint64_t>& pageNotificationIDs, NotificationFilterFunction filterFunction)
{
uint64_t targetPageID = webPage->pageID();
Vector<uint64_t> globalNotificationIDs;
globalNotificationIDs.reserveCapacity(m_globalNotificationMap.size());
for (auto it = m_notifications.begin(), end = m_notifications.end(); it != end; ++it) {
uint64_t webPageID = it->key.first;
uint64_t pageNotificationID = it->key.second;
if (!filterFunction(webPageID, pageNotificationID, targetPageID, pageNotificationIDs))
continue;
uint64_t globalNotificationID = it->value.first;
globalNotificationIDs.append(globalNotificationID);
}
for (auto it = globalNotificationIDs.begin(), end = globalNotificationIDs.end(); it != end; ++it) {
auto pageNotification = m_globalNotificationMap.take(*it);
m_notifications.remove(pageNotification);
}
m_provider->clearNotifications(globalNotificationIDs);
}
void WebNotificationManagerProxy::providerDidShowNotification(uint64_t globalNotificationID)
{
auto it = m_globalNotificationMap.find(globalNotificationID);
if (it == m_globalNotificationMap.end())
return;
uint64_t webPageID = it->value.first;
WebPageProxy* webPage = WebProcessProxy::webPage(webPageID);
if (!webPage)
return;
uint64_t pageNotificationID = it->value.second;
webPage->process().send(Messages::WebNotificationManager::DidShowNotification(pageNotificationID), 0);
}
void WebNotificationManagerProxy::providerDidClickNotification(uint64_t globalNotificationID)
{
auto it = m_globalNotificationMap.find(globalNotificationID);
if (it == m_globalNotificationMap.end())
return;
uint64_t webPageID = it->value.first;
WebPageProxy* webPage = WebProcessProxy::webPage(webPageID);
if (!webPage)
return;
uint64_t pageNotificationID = it->value.second;
webPage->process().send(Messages::WebNotificationManager::DidClickNotification(pageNotificationID), 0);
}
void WebNotificationManagerProxy::providerDidCloseNotifications(API::Array* globalNotificationIDs)
{
HashMap<WebPageProxy*, Vector<uint64_t>> pageNotificationIDs;
size_t size = globalNotificationIDs->size();
for (size_t i = 0; i < size; ++i) {
auto it = m_globalNotificationMap.find(globalNotificationIDs->at<API::UInt64>(i)->value());
if (it == m_globalNotificationMap.end())
continue;
if (WebPageProxy* webPage = WebProcessProxy::webPage(it->value.first)) {
auto pageIt = pageNotificationIDs.find(webPage);
if (pageIt == pageNotificationIDs.end()) {
Vector<uint64_t> newVector;
newVector.reserveInitialCapacity(size);
pageIt = pageNotificationIDs.add(webPage, WTFMove(newVector)).iterator;
}
uint64_t pageNotificationID = it->value.second;
pageIt->value.append(pageNotificationID);
}
m_notifications.remove(it->value);
m_globalNotificationMap.remove(it);
}
for (auto it = pageNotificationIDs.begin(), end = pageNotificationIDs.end(); it != end; ++it)
it->key->process().send(Messages::WebNotificationManager::DidCloseNotifications(it->value), 0);
}
void WebNotificationManagerProxy::providerDidUpdateNotificationPolicy(const API::SecurityOrigin* origin, bool allowed)
{
if (!processPool())
return;
processPool()->sendToAllProcesses(Messages::WebNotificationManager::DidUpdateNotificationDecision(origin->securityOrigin().toString(), allowed));
}
void WebNotificationManagerProxy::providerDidRemoveNotificationPolicies(API::Array* origins)
{
if (!processPool())
return;
size_t size = origins->size();
if (!size)
return;
Vector<String> originStrings;
originStrings.reserveInitialCapacity(size);
for (size_t i = 0; i < size; ++i)
originStrings.append(origins->at<API::SecurityOrigin>(i)->securityOrigin().toString());
processPool()->sendToAllProcesses(Messages::WebNotificationManager::DidRemoveNotificationDecisions(originStrings));
}
uint64_t WebNotificationManagerProxy::notificationLocalIDForTesting(WebNotification* notification)
{
if (!notification)
return 0;
auto it = m_globalNotificationMap.find(notification->notificationID());
if (it == m_globalNotificationMap.end())
return 0;
return it->value.second;
}
} // namespace WebKit