1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "modules/notifications/Notification.h" 33 34 #include "bindings/v8/Dictionary.h" 35 #include "bindings/v8/ScriptWrappable.h" 36 #include "core/dom/Document.h" 37 #include "core/frame/UseCounter.h" 38 #include "core/page/WindowFocusAllowedIndicator.h" 39 #include "modules/notifications/NotificationClient.h" 40 #include "modules/notifications/NotificationController.h" 41 42 namespace WebCore { 43 44 Notification* Notification::create(ExecutionContext* context, const String& title, const Dictionary& options) 45 { 46 NotificationClient& client = NotificationController::clientFrom(toDocument(context)->frame()); 47 Notification* notification = adoptRefCountedGarbageCollectedWillBeNoop(new Notification(title, context, &client)); 48 49 String argument; 50 if (options.get("body", argument)) 51 notification->setBody(argument); 52 if (options.get("tag", argument)) 53 notification->setTag(argument); 54 if (options.get("lang", argument)) 55 notification->setLang(argument); 56 if (options.get("dir", argument)) 57 notification->setDir(argument); 58 if (options.get("icon", argument)) { 59 KURL iconUrl = argument.isEmpty() ? KURL() : context->completeURL(argument); 60 if (!iconUrl.isEmpty() && iconUrl.isValid()) 61 notification->setIconUrl(iconUrl); 62 } 63 64 notification->suspendIfNeeded(); 65 return notification; 66 } 67 68 Notification::Notification(const String& title, ExecutionContext* context, NotificationClient* client) 69 : ActiveDOMObject(context) 70 , m_title(title) 71 , m_dir("auto") 72 , m_state(Idle) 73 , m_client(client) 74 , m_asyncRunner(adoptPtr(new AsyncMethodRunner<Notification>(this, &Notification::show))) 75 { 76 ASSERT(m_client); 77 ScriptWrappable::init(this); 78 79 m_asyncRunner->runAsync(); 80 } 81 82 Notification::~Notification() 83 { 84 } 85 86 void Notification::show() 87 { 88 ASSERT(m_state == Idle); 89 if (!toDocument(executionContext())->page()) 90 return; 91 92 if (m_client->checkPermission(executionContext()) != NotificationClient::PermissionAllowed) { 93 dispatchErrorEvent(); 94 return; 95 } 96 97 if (m_client->show(this)) 98 m_state = Showing; 99 } 100 101 void Notification::close() 102 { 103 switch (m_state) { 104 case Idle: 105 break; 106 case Showing: 107 m_client->close(this); 108 break; 109 case Closed: 110 break; 111 } 112 } 113 114 void Notification::dispatchShowEvent() 115 { 116 dispatchEvent(Event::create(EventTypeNames::show)); 117 } 118 119 void Notification::dispatchClickEvent() 120 { 121 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); 122 WindowFocusAllowedIndicator windowFocusAllowed; 123 dispatchEvent(Event::create(EventTypeNames::click)); 124 } 125 126 void Notification::dispatchErrorEvent() 127 { 128 dispatchEvent(Event::create(EventTypeNames::error)); 129 } 130 131 void Notification::dispatchCloseEvent() 132 { 133 dispatchEvent(Event::create(EventTypeNames::close)); 134 m_state = Closed; 135 } 136 137 TextDirection Notification::direction() const 138 { 139 // FIXME: Resolve dir()=="auto" against the document. 140 return dir() == "rtl" ? RTL : LTR; 141 } 142 143 const String& Notification::permissionString(NotificationClient::Permission permission) 144 { 145 DEFINE_STATIC_LOCAL(const String, allowedPermission, ("granted")); 146 DEFINE_STATIC_LOCAL(const String, deniedPermission, ("denied")); 147 DEFINE_STATIC_LOCAL(const String, defaultPermission, ("default")); 148 149 switch (permission) { 150 case NotificationClient::PermissionAllowed: 151 return allowedPermission; 152 case NotificationClient::PermissionDenied: 153 return deniedPermission; 154 case NotificationClient::PermissionNotAllowed: 155 return defaultPermission; 156 } 157 158 ASSERT_NOT_REACHED(); 159 return deniedPermission; 160 } 161 162 const String& Notification::permission(ExecutionContext* context) 163 { 164 ASSERT(toDocument(context)->page()); 165 166 UseCounter::count(context, UseCounter::NotificationPermission); 167 return permissionString(NotificationController::clientFrom(toDocument(context)->frame()).checkPermission(context)); 168 } 169 170 void Notification::requestPermission(ExecutionContext* context, PassOwnPtr<NotificationPermissionCallback> callback) 171 { 172 ASSERT(toDocument(context)->page()); 173 NotificationController::clientFrom(toDocument(context)->frame()).requestPermission(context, callback); 174 } 175 176 bool Notification::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 177 { 178 ASSERT(m_state != Closed); 179 180 return EventTarget::dispatchEvent(event); 181 } 182 183 const AtomicString& Notification::interfaceName() const 184 { 185 return EventTargetNames::Notification; 186 } 187 188 void Notification::stop() 189 { 190 if (m_client) 191 m_client->notificationObjectDestroyed(this); 192 193 if (m_asyncRunner) 194 m_asyncRunner->stop(); 195 196 m_client = 0; 197 m_state = Closed; 198 } 199 200 bool Notification::hasPendingActivity() const 201 { 202 return m_state == Showing || (m_asyncRunner && m_asyncRunner->isActive()); 203 } 204 205 } // namespace WebCore 206