diff options
Diffstat (limited to 'Source/WebCore/Modules/notifications/NotificationCenter.cpp')
-rw-r--r-- | Source/WebCore/Modules/notifications/NotificationCenter.cpp | 101 |
1 files changed, 59 insertions, 42 deletions
diff --git a/Source/WebCore/Modules/notifications/NotificationCenter.cpp b/Source/WebCore/Modules/notifications/NotificationCenter.cpp index 13f77de4a..a9298f752 100644 --- a/Source/WebCore/Modules/notifications/NotificationCenter.cpp +++ b/Source/WebCore/Modules/notifications/NotificationCenter.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Google Inc. All rights reserved. - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2015 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 @@ -35,30 +35,40 @@ #include "NotificationCenter.h" -#include "Document.h" -#include "NotificationClient.h" +#include "ExceptionCode.h" +#include "Notification.h" +#include "ScriptExecutionContext.h" #include "SecurityOrigin.h" -#include "WorkerGlobalScope.h" +#include "VoidCallback.h" namespace WebCore { -PassRefPtr<NotificationCenter> NotificationCenter::create(ScriptExecutionContext* context, NotificationClient* client) +Ref<NotificationCenter> NotificationCenter::create(ScriptExecutionContext& context, NotificationClient* client) { - RefPtr<NotificationCenter> notificationCenter(adoptRef(new NotificationCenter(context, client))); + auto notificationCenter = adoptRef(*new NotificationCenter(context, client)); notificationCenter->suspendIfNeeded(); - return notificationCenter.release(); + return notificationCenter; } -NotificationCenter::NotificationCenter(ScriptExecutionContext* context, NotificationClient* client) - : ActiveDOMObject(context) +NotificationCenter::NotificationCenter(ScriptExecutionContext& context, NotificationClient* client) + : ActiveDOMObject(&context) , m_client(client) + , m_timer([this]() { timerFired(); }) { } #if ENABLE(LEGACY_NOTIFICATIONS) + +ExceptionOr<Ref<Notification>> NotificationCenter::createNotification(const String& iconURI, const String& title, const String& body) +{ + if (!m_client || !scriptExecutionContext()) + return Exception { INVALID_STATE_ERR }; + return Notification::create(title, body, iconURI, *scriptExecutionContext(), *this); +} + int NotificationCenter::checkPermission() { - if (!client() || !scriptExecutionContext()) + if (!m_client || !scriptExecutionContext()) return NotificationClient::PermissionDenied; switch (scriptExecutionContext()->securityOrigin()->canShowNotifications()) { @@ -73,67 +83,74 @@ int NotificationCenter::checkPermission() ASSERT_NOT_REACHED(); return m_client->checkPermission(scriptExecutionContext()); } -#endif -#if ENABLE(LEGACY_NOTIFICATIONS) -void NotificationCenter::requestPermission(PassRefPtr<VoidCallback> callback) +void NotificationCenter::requestPermission(RefPtr<VoidCallback>&& callback) { - if (!client() || !scriptExecutionContext()) + if (!m_client || !scriptExecutionContext()) return; switch (scriptExecutionContext()->securityOrigin()->canShowNotifications()) { case SecurityOrigin::AlwaysAllow: - case SecurityOrigin::AlwaysDeny: { - m_callbacks.add(NotificationRequestCallback::createAndStartTimer(this, callback)); + case SecurityOrigin::AlwaysDeny: + if (m_callbacks.isEmpty()) { + ref(); // Balanced by the derefs in NotificationCenter::stop and NotificationCenter::timerFired. + m_timer.startOneShot(0); + } + m_callbacks.append([callback]() { + if (callback) + callback->handleEvent(); + }); return; - } case SecurityOrigin::Ask: - return m_client->requestPermission(scriptExecutionContext(), callback); + m_client->requestPermission(scriptExecutionContext(), WTFMove(callback)); + return; } ASSERT_NOT_REACHED(); - m_client->requestPermission(scriptExecutionContext(), callback); + m_client->requestPermission(scriptExecutionContext(), WTFMove(callback)); } + #endif void NotificationCenter::stop() { if (!m_client) return; - m_client->cancelRequestsForPermission(scriptExecutionContext()); - m_client->clearNotifications(scriptExecutionContext()); - m_client = 0; -} -void NotificationCenter::requestTimedOut(NotificationCenter::NotificationRequestCallback* request) -{ - m_callbacks.remove(request); -} + // Clear m_client immediately to guarantee reentrant calls to NotificationCenter do nothing. + // Also protect |this| so it's not indirectly destroyed under us by work done by the client. + auto& client = *std::exchange(m_client, nullptr); + Ref<NotificationCenter> protectedThis(*this); -PassRefPtr<NotificationCenter::NotificationRequestCallback> NotificationCenter::NotificationRequestCallback::createAndStartTimer(NotificationCenter* center, PassRefPtr<VoidCallback> callback) -{ - RefPtr<NotificationCenter::NotificationRequestCallback> requestCallback = adoptRef(new NotificationCenter::NotificationRequestCallback(center, callback)); - requestCallback->startTimer(); - return requestCallback.release(); + if (!m_callbacks.isEmpty()) + deref(); // Balanced by the ref in NotificationCenter::requestPermission. + + m_timer.stop(); + m_callbacks.clear(); + + client.cancelRequestsForPermission(scriptExecutionContext()); + client.clearNotifications(scriptExecutionContext()); } -NotificationCenter::NotificationRequestCallback::NotificationRequestCallback(NotificationCenter* center, PassRefPtr<VoidCallback> callback) - : m_notificationCenter(center) - , m_timer(this, &NotificationCenter::NotificationRequestCallback::timerFired) - , m_callback(callback) +const char* NotificationCenter::activeDOMObjectName() const { + return "NotificationCenter"; } -void NotificationCenter::NotificationRequestCallback::startTimer() +bool NotificationCenter::canSuspendForDocumentSuspension() const { - m_timer.startOneShot(0); + // We don't need to worry about Notifications because those are ActiveDOMObject too. + // The NotificationCenter can safely be suspended if there are no pending permission requests. + return m_callbacks.isEmpty() && (!m_client || !m_client->hasPendingPermissionRequests(scriptExecutionContext())); } -void NotificationCenter::NotificationRequestCallback::timerFired(Timer<NotificationCenter::NotificationRequestCallback>&) +void NotificationCenter::timerFired() { - if (m_callback) - m_callback->handleEvent(); - m_notificationCenter->requestTimedOut(this); + ASSERT(m_client); + auto callbacks = WTFMove(m_callbacks); + for (auto& callback : callbacks) + callback(); + deref(); // Balanced by the ref in NotificationCenter::requestPermission. } } // namespace WebCore |