summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/notifications/NotificationCenter.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/Modules/notifications/NotificationCenter.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/Modules/notifications/NotificationCenter.cpp')
-rw-r--r--Source/WebCore/Modules/notifications/NotificationCenter.cpp101
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