[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebCore / Modules / notifications / Notification.cpp
index 36ae61f..0ebaff8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 Google Inc. All rights reserved.
- * Copyright (C) 2009, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2011, 2012, 2016 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
 
 #include "config.h"
 
-#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
+#if ENABLE(NOTIFICATIONS)
 
 #include "Notification.h"
 
-#include "DOMWindow.h"
-#include "DOMWindowNotifications.h"
-#include "Dictionary.h"
 #include "Document.h"
-#include "ErrorEvent.h"
+#include "Event.h"
 #include "EventNames.h"
-#include "NotificationCenter.h"
 #include "NotificationClient.h"
 #include "NotificationController.h"
 #include "NotificationPermissionCallback.h"
-#include "ResourceRequest.h"
-#include "ResourceResponse.h"
-#include "ThreadableLoader.h"
 #include "WindowFocusAllowedIndicator.h"
-#include "WorkerGlobalScope.h"
+#include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
 
-Notification::Notification()
-    : ActiveDOMObject(0)
+WTF_MAKE_ISO_ALLOCATED_IMPL(Notification);
+
+Ref<Notification> Notification::create(Document& context, const String& title, const Options& options)
 {
+    auto notification = adoptRef(*new Notification(context, title, options));
+    notification->suspendIfNeeded();
+    return notification;
 }
 
-#if ENABLE(LEGACY_NOTIFICATIONS)
-Notification::Notification(const String& title, const String& body, const String& iconURI, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider)
-    : ActiveDOMObject(context)
+Notification::Notification(Document& document, const String& title, const Options& options)
+    : ActiveDOMObject(document)
     , m_title(title)
-    , m_body(body)
+    , m_direction(options.dir)
+    , m_lang(options.lang)
+    , m_body(options.body)
+    , m_tag(options.tag)
     , m_state(Idle)
-    , m_notificationCenter(provider)
+    , m_taskTimer(makeUnique<Timer>([this] () { show(); }))
 {
-    if (m_notificationCenter->checkPermission() != NotificationClient::PermissionAllowed) {
-        ec = SECURITY_ERR;
-        return;
+    if (!options.icon.isEmpty()) {
+        auto iconURL = document.completeURL(options.icon);
+        if (iconURL.isValid())
+            m_icon = iconURL;
     }
 
-    m_icon = iconURI.isEmpty() ? URL() : scriptExecutionContext()->completeURL(iconURI);
-    if (!m_icon.isEmpty() && !m_icon.isValid()) {
-        ec = SYNTAX_ERR;
-        return;
-    }
+    m_taskTimer->startOneShot(0_s);
 }
-#endif
 
-#if ENABLE(NOTIFICATIONS)
-Notification::Notification(ScriptExecutionContext& context, const String& title)
-    : ActiveDOMObject(&context)
-    , m_title(title)
-    , m_state(Idle)
-    , m_taskTimer(std::make_unique<Timer<Notification>>(this, &Notification::taskTimerFired))
-{
-    m_notificationCenter = DOMWindowNotifications::webkitNotifications(downcast<Document>(context).domWindow());
-    
-    ASSERT(m_notificationCenter->client());
-    m_taskTimer->startOneShot(0);
-}
-#endif
+Notification::~Notification()  = default;
 
-Notification::~Notification() 
+void Notification::show()
 {
-}
-
-#if ENABLE(LEGACY_NOTIFICATIONS)
-PassRef<Notification> Notification::create(const String& title, const String& body, const String& iconURI, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider) 
-{ 
-    auto notification = adoptRef(*new Notification(title, body, iconURI, context, ec, provider));
-    notification.get().suspendIfNeeded();
-    return notification;
-}
-#endif
+    // prevent double-showing
+    if (m_state != Idle)
+        return;
 
-#if ENABLE(NOTIFICATIONS)
-PassRef<Notification> Notification::create(ScriptExecutionContext& context, const String& title, const Dictionary& options)
-{
-    auto notification = adoptRef(*new Notification(context, title));
-    String argument;
-    if (options.get("body", argument))
-        notification.get().setBody(argument);
-    if (options.get("tag", argument))
-        notification.get().setTag(argument);
-    if (options.get("lang", argument))
-        notification.get().setLang(argument);
-    if (options.get("dir", argument))
-        notification.get().setDir(argument);
-    if (options.get("icon", argument)) {
-        URL iconURI = argument.isEmpty() ? URL() : context.completeURL(argument);
-        if (!iconURI.isEmpty() && iconURI.isValid())
-            notification.get().setIconURL(iconURI);
-    }
+    auto* page = downcast<Document>(*scriptExecutionContext()).page();
+    if (!page)
+        return;
 
-    notification.get().suspendIfNeeded();
-    return notification;
-}
-#endif
+    auto& client = NotificationController::from(page)->client();
 
-void Notification::show() 
-{
-    // prevent double-showing
-    if (m_state == Idle && m_notificationCenter->client()) {
-#if ENABLE(NOTIFICATIONS)
-        if (!downcast<Document>(*scriptExecutionContext()).page())
-            return;
-        if (NotificationController::from(downcast<Document>(*scriptExecutionContext()).page())->client()->checkPermission(scriptExecutionContext()) != NotificationClient::PermissionAllowed) {
-            dispatchErrorEvent();
-            return;
-        }
-#endif
-        if (m_notificationCenter->client()->show(this)) {
-            m_state = Showing;
-            setPendingActivity(this);
-        }
+    if (client.checkPermission(scriptExecutionContext()) != Permission::Granted) {
+        dispatchErrorEvent();
+        return;
+    }
+    if (client.show(this)) {
+        m_state = Showing;
+        setPendingActivity(*this);
     }
 }
 
@@ -154,20 +103,35 @@ void Notification::close()
     switch (m_state) {
     case Idle:
         break;
-    case Showing:
-        if (m_notificationCenter->client())
-            m_notificationCenter->client()->cancel(this);
+    case Showing: {
+        auto* page = downcast<Document>(*scriptExecutionContext()).page();
+        if (page)
+            NotificationController::from(page)->client().cancel(this);
         break;
+    }
     case Closed:
         break;
     }
 }
 
-void Notification::contextDestroyed()
+const char* Notification::activeDOMObjectName() const
 {
-    ActiveDOMObject::contextDestroyed();
-    if (m_notificationCenter->client())
-        m_notificationCenter->client()->notificationObjectDestroyed(this);
+    return "Notification";
+}
+
+bool Notification::canSuspendForDocumentSuspension() const
+{
+    // We can suspend if the Notification is not shown yet or after it is closed.
+    return m_state == Idle || m_state == Closed;
+}
+
+void Notification::stop()
+{
+    ActiveDOMObject::stop();
+
+    auto* page = downcast<Document>(*scriptExecutionContext()).page();
+    if (page)
+        NotificationController::from(page)->client().notificationObjectDestroyed(this);
 }
 
 void Notification::finalize()
@@ -175,70 +139,41 @@ void Notification::finalize()
     if (m_state == Closed)
         return;
     m_state = Closed;
-    unsetPendingActivity(this);
+    unsetPendingActivity(*this);
 }
 
 void Notification::dispatchShowEvent()
 {
-    dispatchEvent(Event::create(eventNames().showEvent, false, false));
+    dispatchEvent(Event::create(eventNames().showEvent, Event::CanBubble::No, Event::IsCancelable::No));
 }
 
 void Notification::dispatchClickEvent()
 {
     WindowFocusAllowedIndicator windowFocusAllowed;
-    dispatchEvent(Event::create(eventNames().clickEvent, false, false));
+    dispatchEvent(Event::create(eventNames().clickEvent, Event::CanBubble::No, Event::IsCancelable::No));
 }
 
 void Notification::dispatchCloseEvent()
 {
-    dispatchEvent(Event::create(eventNames().closeEvent, false, false));
+    dispatchEvent(Event::create(eventNames().closeEvent, Event::CanBubble::No, Event::IsCancelable::No));
     finalize();
 }
 
 void Notification::dispatchErrorEvent()
 {
-    dispatchEvent(Event::create(eventNames().errorEvent, false, false));
+    dispatchEvent(Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No));
 }
 
-#if ENABLE(NOTIFICATIONS)
-void Notification::taskTimerFired(Timer<Notification>& timer)
+auto Notification::permission(Document& document) -> Permission
 {
-    ASSERT(scriptExecutionContext()->isDocument());
-    ASSERT_UNUSED(timer, &timer == m_taskTimer.get());
-    show();
-}
-#endif
-
-
-#if ENABLE(NOTIFICATIONS)
-const String Notification::permission(ScriptExecutionContext* context)
-{
-    ASSERT(downcast<Document>(*context).page());
-    return permissionString(NotificationController::from(downcast<Document>(*context).page())->client()->checkPermission(context));
-}
-
-const String Notification::permissionString(NotificationClient::Permission permission)
-{
-    switch (permission) {
-    case NotificationClient::PermissionAllowed:
-        return ASCIILiteral("granted");
-    case NotificationClient::PermissionDenied:
-        return ASCIILiteral("denied");
-    case NotificationClient::PermissionNotAllowed:
-        return ASCIILiteral("default");
-    }
-    
-    ASSERT_NOT_REACHED();
-    return String();
+    return NotificationController::from(document.page())->client().checkPermission(&document);
 }
 
-void Notification::requestPermission(ScriptExecutionContext* context, PassRefPtr<NotificationPermissionCallback> callback)
+void Notification::requestPermission(Document& document, RefPtr<NotificationPermissionCallback>&& callback)
 {
-    ASSERT(downcast<Document>(*context).page());
-    NotificationController::from(downcast<Document>(*context).page())->client()->requestPermission(context, callback);
+    NotificationController::from(document.page())->client().requestPermission(&document, WTFMove(callback));
 }
-#endif
 
 } // namespace WebCore
 
-#endif // ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
+#endif // ENABLE(NOTIFICATIONS)