Reduce amount of rebuilding when touching networking headers
[WebKit-https.git] / Source / WebCore / Modules / notifications / Notification.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  * Copyright (C) 2009, 2011, 2012 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33
34 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
35
36 #include "Notification.h"
37
38 #include "DOMWindow.h"
39 #include "DOMWindowNotifications.h"
40 #include "Dictionary.h"
41 #include "Document.h"
42 #include "ErrorEvent.h"
43 #include "EventNames.h"
44 #include "NotificationCenter.h"
45 #include "NotificationClient.h"
46 #include "NotificationController.h"
47 #include "NotificationPermissionCallback.h"
48 #include "WindowFocusAllowedIndicator.h"
49
50 namespace WebCore {
51
52 Notification::Notification()
53     : ActiveDOMObject(0, this)
54 {
55 }
56
57 #if ENABLE(LEGACY_NOTIFICATIONS)
58 Notification::Notification(const KURL& url, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider)
59     : ActiveDOMObject(context, this)
60     , m_isHTML(true)
61     , m_state(Idle)
62     , m_notificationCenter(provider)
63 {
64     if (m_notificationCenter->checkPermission() != NotificationClient::PermissionAllowed) {
65         ec = SECURITY_ERR;
66         return;
67     }
68
69     if (url.isEmpty() || !url.isValid()) {
70         ec = SYNTAX_ERR;
71         return;
72     }
73
74     m_notificationURL = url;
75 }
76 #endif
77
78 #if ENABLE(LEGACY_NOTIFICATIONS)
79 Notification::Notification(const String& title, const String& body, const String& iconURI, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider)
80     : ActiveDOMObject(context, this)
81     , m_isHTML(false)
82     , m_title(title)
83     , m_body(body)
84     , m_state(Idle)
85     , m_notificationCenter(provider)
86 {
87     if (m_notificationCenter->checkPermission() != NotificationClient::PermissionAllowed) {
88         ec = SECURITY_ERR;
89         return;
90     }
91
92     m_icon = iconURI.isEmpty() ? KURL() : scriptExecutionContext()->completeURL(iconURI);
93     if (!m_icon.isEmpty() && !m_icon.isValid()) {
94         ec = SYNTAX_ERR;
95         return;
96     }
97 }
98 #endif
99
100 #if ENABLE(NOTIFICATIONS)
101 Notification::Notification(ScriptExecutionContext* context, const String& title)
102     : ActiveDOMObject(context, this)
103     , m_isHTML(false)
104     , m_title(title)
105     , m_state(Idle)
106     , m_taskTimer(adoptPtr(new Timer<Notification>(this, &Notification::taskTimerFired)))
107 {
108     ASSERT_WITH_SECURITY_IMPLICATION(context->isDocument());
109     m_notificationCenter = DOMWindowNotifications::webkitNotifications(static_cast<Document*>(context)->domWindow());
110     
111     ASSERT(m_notificationCenter->client());
112     m_taskTimer->startOneShot(0);
113 }
114 #endif
115
116 Notification::~Notification() 
117 {
118 }
119
120 #if ENABLE(LEGACY_NOTIFICATIONS)
121 PassRefPtr<Notification> Notification::create(const KURL& url, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider) 
122
123     RefPtr<Notification> notification(adoptRef(new Notification(url, context, ec, provider)));
124     notification->suspendIfNeeded();
125     return notification.release();
126 }
127
128 PassRefPtr<Notification> Notification::create(const String& title, const String& body, const String& iconURI, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider) 
129
130     RefPtr<Notification> notification(adoptRef(new Notification(title, body, iconURI, context, ec, provider)));
131     notification->suspendIfNeeded();
132     return notification.release();
133 }
134 #endif
135
136 #if ENABLE(NOTIFICATIONS)
137 PassRefPtr<Notification> Notification::create(ScriptExecutionContext* context, const String& title, const Dictionary& options)
138 {
139     RefPtr<Notification> notification(adoptRef(new Notification(context, title)));
140     String argument;
141     if (options.get("body", argument))
142         notification->setBody(argument);
143     if (options.get("tag", argument))
144         notification->setTag(argument);
145     if (options.get("lang", argument))
146         notification->setLang(argument);
147     if (options.get("dir", argument))
148         notification->setDir(argument);
149     if (options.get("icon", argument)) {
150         KURL iconURI = argument.isEmpty() ? KURL() : context->completeURL(argument);
151         if (!iconURI.isEmpty() && iconURI.isValid())
152             notification->setIconURL(iconURI);
153     }
154
155     notification->suspendIfNeeded();
156     return notification.release();
157 }
158 #endif
159
160 const AtomicString& Notification::interfaceName() const
161 {
162     return eventNames().interfaceForNotification;
163 }
164
165 void Notification::show() 
166 {
167     // prevent double-showing
168     if (m_state == Idle && m_notificationCenter->client()) {
169 #if ENABLE(NOTIFICATIONS)
170         if (!static_cast<Document*>(scriptExecutionContext())->page())
171             return;
172         if (NotificationController::from(static_cast<Document*>(scriptExecutionContext())->page())->client()->checkPermission(scriptExecutionContext()) != NotificationClient::PermissionAllowed) {
173             dispatchErrorEvent();
174             return;
175         }
176 #endif
177         if (m_notificationCenter->client()->show(this)) {
178             m_state = Showing;
179             setPendingActivity(this);
180         }
181     }
182 }
183
184 void Notification::close()
185 {
186     switch (m_state) {
187     case Idle:
188         break;
189     case Showing:
190         if (m_notificationCenter->client())
191             m_notificationCenter->client()->cancel(this);
192         break;
193     case Closed:
194         break;
195     }
196 }
197
198 EventTargetData* Notification::eventTargetData()
199 {
200     return &m_eventTargetData;
201 }
202
203 EventTargetData* Notification::ensureEventTargetData()
204 {
205     return &m_eventTargetData;
206 }
207
208 void Notification::contextDestroyed()
209 {
210     ActiveDOMObject::contextDestroyed();
211     if (m_notificationCenter->client())
212         m_notificationCenter->client()->notificationObjectDestroyed(this);
213 }
214
215 void Notification::finalize()
216 {
217     if (m_state == Closed)
218         return;
219     m_state = Closed;
220     unsetPendingActivity(this);
221 }
222
223 void Notification::dispatchShowEvent()
224 {
225     dispatchEvent(Event::create(eventNames().showEvent, false, false));
226 }
227
228 void Notification::dispatchClickEvent()
229 {
230     WindowFocusAllowedIndicator windowFocusAllowed;
231     dispatchEvent(Event::create(eventNames().clickEvent, false, false));
232 }
233
234 void Notification::dispatchCloseEvent()
235 {
236     dispatchEvent(Event::create(eventNames().closeEvent, false, false));
237     finalize();
238 }
239
240 void Notification::dispatchErrorEvent()
241 {
242     dispatchEvent(Event::create(eventNames().errorEvent, false, false));
243 }
244
245 #if ENABLE(NOTIFICATIONS)
246 void Notification::taskTimerFired(Timer<Notification>* timer)
247 {
248     ASSERT(scriptExecutionContext()->isDocument());
249     ASSERT_UNUSED(timer, timer == m_taskTimer.get());
250     show();
251 }
252 #endif
253
254
255 #if ENABLE(NOTIFICATIONS)
256 const String& Notification::permission(ScriptExecutionContext* context)
257 {
258     ASSERT_WITH_SECURITY_IMPLICATION(context->isDocument());
259     ASSERT(static_cast<Document*>(context)->page());
260     return permissionString(NotificationController::from(static_cast<Document*>(context)->page())->client()->checkPermission(context));
261 }
262
263 const String& Notification::permissionString(NotificationClient::Permission permission)
264 {
265     DEFINE_STATIC_LOCAL(const String, allowedPermission, (ASCIILiteral("granted")));
266     DEFINE_STATIC_LOCAL(const String, deniedPermission, (ASCIILiteral("denied")));
267     DEFINE_STATIC_LOCAL(const String, defaultPermission, (ASCIILiteral("default")));
268
269     switch (permission) {
270     case NotificationClient::PermissionAllowed:
271         return allowedPermission;
272     case NotificationClient::PermissionDenied:
273         return deniedPermission;
274     case NotificationClient::PermissionNotAllowed:
275         return defaultPermission;
276     }
277     
278     ASSERT_NOT_REACHED();
279     return deniedPermission;
280 }
281
282 void Notification::requestPermission(ScriptExecutionContext* context, PassRefPtr<NotificationPermissionCallback> callback)
283 {
284     ASSERT_WITH_SECURITY_IMPLICATION(context->isDocument());
285     ASSERT(static_cast<Document*>(context)->page());
286     NotificationController::from(static_cast<Document*>(context)->page())->client()->requestPermission(context, callback);
287 }
288 #endif
289
290 } // namespace WebCore
291
292 #endif // ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)