diff options
-rw-r--r-- | build/features_override.gypi | 2 | ||||
-rwxr-xr-x | chrome/chrome.gyp | 4 | ||||
-rw-r--r-- | chrome/common/desktop_notifications/active_notification_tracker.cc | 69 | ||||
-rw-r--r-- | chrome/common/desktop_notifications/active_notification_tracker.h | 50 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 41 | ||||
-rw-r--r-- | chrome/renderer/notification_provider.cc | 160 | ||||
-rw-r--r-- | chrome/renderer/notification_provider.h | 70 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 5 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 8 | ||||
-rw-r--r-- | webkit/api/public/WebNotification.h | 7 | ||||
-rw-r--r-- | webkit/api/src/WebNotification.cpp | 14 |
11 files changed, 426 insertions, 4 deletions
diff --git a/build/features_override.gypi b/build/features_override.gypi index 2023705..ecd686c 100644 --- a/build/features_override.gypi +++ b/build/features_override.gypi @@ -20,7 +20,7 @@ 'ENABLE_JAVASCRIPT_DEBUGGER=0', 'ENABLE_JSC_MULTIPLE_THREADS=0', 'ENABLE_ICONDATABASE=0', - 'ENABLE_NOTIFICATIONS=0', + 'ENABLE_NOTIFICATIONS=1', 'ENABLE_ORIENTATION_EVENTS=0', 'ENABLE_XSLT=1', 'ENABLE_XPATH=1', diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index c002bd7..8f80034 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -485,6 +485,8 @@ ], 'sources': [ # All .cc, .h, and .mm files under chrome/common except for tests. + 'common/desktop_notifications/active_notification_tracker.h', + 'common/desktop_notifications/active_notification_tracker.cc', 'common/extensions/extension.cc', 'common/extensions/extension.h', 'common/extensions/extension_constants.cc', @@ -3073,6 +3075,8 @@ 'renderer/localized_error.cc', 'renderer/localized_error.h', 'renderer/navigation_state.h', + 'renderer/notification_provider.cc', + 'renderer/notification_provider.h', 'renderer/plugin_channel_host.cc', 'renderer/plugin_channel_host.h', 'renderer/print_web_view_helper.cc', diff --git a/chrome/common/desktop_notifications/active_notification_tracker.cc b/chrome/common/desktop_notifications/active_notification_tracker.cc new file mode 100644 index 0000000..230d76a --- /dev/null +++ b/chrome/common/desktop_notifications/active_notification_tracker.cc @@ -0,0 +1,69 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/desktop_notifications/active_notification_tracker.h" + +#include "base/message_loop.h" +#include "webkit/api/public/WebNotification.h" +#include "webkit/api/public/WebNotificationPermissionCallback.h" + +using WebKit::WebNotification; +using WebKit::WebNotificationPermissionCallback; + +bool ActiveNotificationTracker::GetId( + const WebNotification& notification, int& id) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + ReverseTable::iterator iter = reverse_notification_table_.find(notification); + if (iter == reverse_notification_table_.end()) + return false; + id = iter->second; + return true; +} + +bool ActiveNotificationTracker::GetNotification( + int id, WebNotification* notification) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + WebNotification* lookup = notification_table_.Lookup(id); + if (!lookup) + return false; + + *notification = *lookup; + return true; +} + +int ActiveNotificationTracker::RegisterNotification( + const WebKit::WebNotification& proxy) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + WebNotification* notification = new WebNotification(proxy); + int id = notification_table_.Add(notification); + reverse_notification_table_[proxy] = id; + return id; +} + +void ActiveNotificationTracker::UnregisterNotification(int id) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + // We want to free the notification after removing it from the table. + scoped_ptr<WebNotification> notification(notification_table_.Lookup(id)); + notification_table_.Remove(id); + DCHECK(notification.get()); + if (notification.get()) + reverse_notification_table_.erase(*notification); +} + +WebNotificationPermissionCallback* ActiveNotificationTracker::GetCallback( + int id) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + return callback_table_.Lookup(id); +} + +int ActiveNotificationTracker::RegisterPermissionRequest( + WebNotificationPermissionCallback* callback) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + return callback_table_.Add(callback); +} + +void ActiveNotificationTracker::OnPermissionRequestComplete(int id) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + callback_table_.Remove(id); +} diff --git a/chrome/common/desktop_notifications/active_notification_tracker.h b/chrome/common/desktop_notifications/active_notification_tracker.h new file mode 100644 index 0000000..4bdd5d9 --- /dev/null +++ b/chrome/common/desktop_notifications/active_notification_tracker.h @@ -0,0 +1,50 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_DESKTOP_NOTIFICATIONS_ACTIVE_NOTIFICATION_TRACKER_H_ +#define CHROME_COMMON_DESKTOP_NOTIFICATIONS_ACTIVE_NOTIFICATION_TRACKER_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/id_map.h" +#include "base/hash_tables.h" +#include "webkit/api/public/WebNotification.h" + +namespace WebKit { +class WebNotificationPermissionCallback; +} + +// This class manages the set of active Notification objects in either +// a render or worker process. This class should be accessed only on +// the main thread. +class ActiveNotificationTracker { + public: + ActiveNotificationTracker() {} + + // Methods for tracking active notification objects. + int RegisterNotification(const WebKit::WebNotification& notification); + void UnregisterNotification(int id); + bool GetId(const WebKit::WebNotification& notification, int& id); + bool GetNotification(int id, WebKit::WebNotification* notification); + + // Methods for tracking active permission requests. + int RegisterPermissionRequest( + WebKit::WebNotificationPermissionCallback* callback); + void OnPermissionRequestComplete(int id); + WebKit::WebNotificationPermissionCallback* GetCallback(int id); + + private: + typedef std::map<WebKit::WebNotification, int> ReverseTable; + + // Tracking maps for active notifications and permission requests. + IDMap<WebKit::WebNotification> notification_table_; + ReverseTable reverse_notification_table_; + IDMap<WebKit::WebNotificationPermissionCallback> callback_table_; + + DISALLOW_COPY_AND_ASSIGN(ActiveNotificationTracker); +}; + +#endif // CHROME_COMMON_DESKTOP_NOTIFICATIONS_ACTIVE_NOTIFICATION_TRACKER_H_ + diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 804e624..62451cc 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -689,6 +689,26 @@ IPC_BEGIN_MESSAGES(View) // width. IPC_MESSAGE_ROUTED0(ViewMsg_EnableIntrinsicWidthChangedMode) + // Used to inform the renderer that the browser has displayed its + // requested notification. + IPC_MESSAGE_ROUTED1(ViewMsg_PostDisplayToNotificationObject, + int /* notification_id */) + + // Used to inform the renderer that the browser has encountered an error + // trying to display a notification. + IPC_MESSAGE_ROUTED2(ViewMsg_PostErrorToNotificationObject, + int /* notification_id */, + string16 /* message */) + + // Informs the renderer that the one if its notifications has closed. + IPC_MESSAGE_ROUTED2(ViewMsg_PostCloseToNotificationObject, + int /* notification_id */, + bool /* by_user */) + + // Informs the renderer that the one if its notifications has closed. + IPC_MESSAGE_ROUTED1(ViewMsg_PermissionRequestDone, + int /* request_id */) + // Activate/deactivate the RenderView (i.e., set its controls' tint // accordingly, etc.). IPC_MESSAGE_ROUTED1(ViewMsg_SetActive, @@ -1622,6 +1642,27 @@ IPC_BEGIN_MESSAGES(ViewHost) int /* render_view_route_id */, int /* route_id */) + // A message sent to the browser on behalf of a renderer which wants to show + // a desktop notification. + IPC_MESSAGE_ROUTED3(ViewHostMsg_ShowDesktopNotification, + GURL /* origin */, + GURL /* contents_url */, + int /* notification_id */) + IPC_MESSAGE_ROUTED5(ViewHostMsg_ShowDesktopNotificationText, + GURL /* origin */, + GURL /* icon_url */, + string16 /* title */, + string16 /* text */, + int /* notification_id */) + IPC_MESSAGE_ROUTED1(ViewHostMsg_CancelDesktopNotification, + int /* notification_id */ ) + IPC_MESSAGE_ROUTED2(ViewHostMsg_RequestNotificationPermission, + string16 /* origin */, + int /* callback_context */) + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_CheckNotificationPermission, + string16 /* origin */, + int /* permission_result */) + // Sent if the worker object has sent a ViewHostMsg_CreateDedicatedWorker // message and not received a ViewMsg_DedicatedWorkerCreated reply, but in the // mean time it's destroyed. This tells the browser to not create the queued diff --git a/chrome/renderer/notification_provider.cc b/chrome/renderer/notification_provider.cc new file mode 100644 index 0000000..f6baba8 --- /dev/null +++ b/chrome/renderer/notification_provider.cc @@ -0,0 +1,160 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/notification_provider.h" + +#include "base/task.h" +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_thread.h" +#include "chrome/renderer/render_view.h" +#include "webkit/api/public/WebNotificationPermissionCallback.h" + +using WebKit::WebNotification; +using WebKit::WebNotificationPresenter; +using WebKit::WebNotificationPermissionCallback; +using WebKit::WebString; + +NotificationProvider::NotificationProvider(RenderView* view) + : view_(view) { +} + +bool NotificationProvider::show(const WebNotification& notification) { + int notification_id = manager_.RegisterNotification(notification); + if (notification.isHTML()) + return ShowHTML(notification, notification_id); + else + return ShowText(notification, notification_id); +} + +void NotificationProvider::cancel(const WebNotification& notification) { + int id; + bool id_found = manager_.GetId(notification, id); + DCHECK(id_found); + if (id_found) + Send(new ViewHostMsg_CancelDesktopNotification(view_->routing_id(), id)); +} + +void NotificationProvider::objectDestroyed( + const WebNotification& notification) { + int id; + bool id_found = manager_.GetId(notification, id); + DCHECK(id_found); + if (id_found) + manager_.UnregisterNotification(id); +} + +WebNotificationPresenter::Permission NotificationProvider::checkPermission( + const WebString& origin) { + int permission; + Send(new ViewHostMsg_CheckNotificationPermission(view_->routing_id(), origin, + &permission)); + return static_cast<WebNotificationPresenter::Permission>(permission); +} + +void NotificationProvider::requestPermission( + const WebString& origin, WebNotificationPermissionCallback* callback) { + int id = manager_.RegisterPermissionRequest(callback); + + Send(new ViewHostMsg_RequestNotificationPermission(view_->routing_id(), + origin, id)); +} + +bool NotificationProvider::ShowHTML(const WebNotification& notification, + int id) { + DCHECK(notification.isHTML()); + return Send(new ViewHostMsg_ShowDesktopNotification(view_->routing_id(), + GURL(view_->webview()->mainFrame()->url()), + notification.url(), id)); +} + +bool NotificationProvider::ShowText(const WebNotification& notification, + int id) { + DCHECK(!notification.isHTML()); + return Send(new ViewHostMsg_ShowDesktopNotificationText(view_->routing_id(), + GURL(view_->webview()->mainFrame()->url()), + GURL(notification.icon()), + notification.title(), notification.body(), id)); +} + +void NotificationProvider::OnDisplay(int id) { + RenderProcess::current()->main_thread()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &NotificationProvider::HandleOnDisplay, id)); +} + +void NotificationProvider::OnError(int id, const WebString& message) { + RenderProcess::current()->main_thread()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &NotificationProvider::HandleOnError, + id, message)); +} + +void NotificationProvider::OnClose(int id, bool by_user) { + RenderProcess::current()->main_thread()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &NotificationProvider::HandleOnClose, + id, by_user)); +} + +void NotificationProvider::OnPermissionRequestComplete(int id) { + RenderProcess::current()->main_thread()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, + &NotificationProvider::HandleOnPermissionRequestComplete, id)); +} + +void NotificationProvider::HandleOnDisplay(int id) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + WebNotification notification; + bool found = manager_.GetNotification(id, ¬ification); + // |found| may be false if the WebNotification went out of scope in + // the page before it was actually displayed to the user. + if (found) + notification.dispatchDisplayEvent(); +} + +void NotificationProvider::HandleOnError(int id, const WebString& message) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + WebNotification notification; + bool found = manager_.GetNotification(id, ¬ification); + // |found| may be false if the WebNotification went out of scope in + // the page before the error occurred. + if (found) + notification.dispatchErrorEvent(message); +} + +void NotificationProvider::HandleOnClose(int id, bool by_user) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + WebNotification notification; + bool found = manager_.GetNotification(id, ¬ification); + // |found| may be false if the WebNotification went out of scope in + // the page before the associated toast was closed by the user. + if (found) + notification.dispatchCloseEvent(by_user); + manager_.UnregisterNotification(id); +} + +void NotificationProvider::HandleOnPermissionRequestComplete(int id) { + DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + WebNotificationPermissionCallback* callback = manager_.GetCallback(id); + DCHECK(callback); + callback->permissionRequestComplete(); + manager_.OnPermissionRequestComplete(id); +} + +bool NotificationProvider::OnMessageReceived(const IPC::Message& message) { + if (message.routing_id() != view_->routing_id()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(NotificationProvider, message) + IPC_MESSAGE_HANDLER(ViewMsg_PostDisplayToNotificationObject, OnDisplay); + IPC_MESSAGE_HANDLER(ViewMsg_PostErrorToNotificationObject, OnError); + IPC_MESSAGE_HANDLER(ViewMsg_PostCloseToNotificationObject, OnClose); + IPC_MESSAGE_HANDLER(ViewMsg_PermissionRequestDone, + OnPermissionRequestComplete); + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool NotificationProvider::Send(IPC::Message* message) { + return RenderThread::current()->Send(message); +} diff --git a/chrome/renderer/notification_provider.h b/chrome/renderer/notification_provider.h new file mode 100644 index 0000000..ec0a05c --- /dev/null +++ b/chrome/renderer/notification_provider.h @@ -0,0 +1,70 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_NOTIFICATION_PROVIDER_H_ +#define CHROME_RENDERER_NOTIFICATION_PROVIDER_H_ + +#include <map> + +#include "chrome/common/desktop_notifications/active_notification_tracker.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_channel_proxy.h" +#include "webkit/api/public/WebNotification.h" +#include "webkit/api/public/WebNotificationPresenter.h" + +class RenderView; +namespace WebKit { +class WebNotificationPermissionCallback; +} + +class NotificationProvider : public WebKit::WebNotificationPresenter, + public IPC::ChannelProxy::MessageFilter { + public: + explicit NotificationProvider(RenderView* view); + ~NotificationProvider() {} + + // WebKit::WebNotificationPresenter interface. Called from WebKit + // on the UI thread. + virtual bool show(const WebKit::WebNotification& proxy); + virtual void cancel(const WebKit::WebNotification& proxy); + virtual void objectDestroyed(const WebKit::WebNotification& proxy); + virtual WebKit::WebNotificationPresenter::Permission checkPermission( + const WebKit::WebString& origin); + virtual void requestPermission(const WebKit::WebString& origin, + WebKit::WebNotificationPermissionCallback* callback); + +private: + // Internal methods used on the UI thread. + bool ShowHTML(const WebKit::WebNotification& notification, int id); + bool ShowText(const WebKit::WebNotification& notification, int id); + + // Callback methods invoked when events happen on active notifications. + void OnDisplay(int id); + void OnError(int id, const WebKit::WebString& message); + void OnClose(int id, bool by_user); + void OnPermissionRequestComplete(int id); + + // Internal versions of the IPC handlers which run on the UI thread. + void HandleOnDisplay(int id); + void HandleOnError(int id, const WebKit::WebString& message); + void HandleOnClose(int id, bool by_user); + void HandleOnPermissionRequestComplete(int id); + + // IPC::ChannelProxy::MessageFilter override + virtual bool OnMessageReceived(const IPC::Message& message); + + bool Send(IPC::Message* message); + + // Non-owned pointer to the RenderView object which created and owns + // this object. + RenderView* view_; + + // A tracker object which manages the active notifications and the IDs + // that are used to refer to them over IPC. + ActiveNotificationTracker manager_; + + DISALLOW_COPY_AND_ASSIGN(NotificationProvider); +}; + +#endif // CHROME_RENDERER_NOTIFICATION_PROVIDER_H_ diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 89fba21..bcbda08 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -44,6 +44,7 @@ #include "chrome/renderer/localized_error.h" #include "chrome/renderer/media/audio_renderer_impl.h" #include "chrome/renderer/navigation_state.h" +#include "chrome/renderer/notification_provider.h" #include "chrome/renderer/plugin_channel_host.h" #include "chrome/renderer/print_web_view_helper.h" #include "chrome/renderer/render_process.h" @@ -252,6 +253,7 @@ RenderView::~RenderView() { #endif render_thread_->RemoveFilter(audio_message_filter_); + render_thread_->RemoveFilter(notification_provider_.get()); } /*static*/ @@ -312,6 +314,8 @@ void RenderView::Init(gfx::NativeViewId parent_hwnd, devtools_agent_.reset(new DevToolsAgent(routing_id, this)); + notification_provider_ = new NotificationProvider(this); + webwidget_ = WebView::Create(this); webkit_preferences_.Apply(webview()); webview()->initializeMainFrame(this); @@ -339,6 +343,7 @@ void RenderView::Init(gfx::NativeViewId parent_hwnd, audio_message_filter_ = new AudioMessageFilter(routing_id_); render_thread_->AddFilter(audio_message_filter_); + render_thread_->AddFilter(notification_provider_.get()); } void RenderView::OnMessageReceived(const IPC::Message& message) { diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 5a7dcdd..cdd1c2c 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -29,6 +29,7 @@ #include "chrome/renderer/dom_ui_bindings.h" #include "chrome/renderer/extensions/extension_process_bindings.h" #include "chrome/renderer/external_host_bindings.h" +#include "chrome/renderer/notification_provider.h" #include "chrome/renderer/render_widget.h" #include "third_party/skia/include/core/SkBitmap.h" #include "testing/gtest/include/gtest/gtest_prod.h" @@ -268,6 +269,10 @@ class RenderView : public RenderWidget, virtual void didAddHistoryItem(); virtual void didUpdateInspectorSettings(); + virtual WebKit::WebNotificationPresenter* GetNotificationPresenter() { + return notification_provider_.get(); + } + // WebKit::WebWidgetClient // Most methods are handled by RenderWidget. virtual void show(WebKit::WebNavigationPolicy policy); @@ -903,6 +908,9 @@ class RenderView : public RenderWidget, // The text selection the last time DidChangeSelection got called. std::string last_selection_; + // Hopds a reference to the service which provides desktop notifications. + scoped_refptr<NotificationProvider> notification_provider_; + // Set to true if request for capturing page text has been made. bool determine_page_text_after_loading_stops_; diff --git a/webkit/api/public/WebNotification.h b/webkit/api/public/WebNotification.h index 3d96c48..fb6cd6d 100644 --- a/webkit/api/public/WebNotification.h +++ b/webkit/api/public/WebNotification.h @@ -56,7 +56,9 @@ namespace WebKit { WebNotification& operator=(const WebNotification& other) { assign(other); return *this; } + // Operators required to put WebNotification in an ordered map. bool equals(const WebNotification& other) const { return m_private == other.m_private; } + bool lessThan(const WebNotification& other) const; // Is the notification HTML vs. icon-title-text? WEBKIT_API bool isHTML() const; @@ -101,6 +103,11 @@ namespace WebKit { return !a.equals(b); } + inline bool operator<(const WebNotification& a, const WebNotification& b) + { + return a.lessThan(b); + } + } // namespace WebKit #endif diff --git a/webkit/api/src/WebNotification.cpp b/webkit/api/src/WebNotification.cpp index 46baab7..2b2e3bb 100644 --- a/webkit/api/src/WebNotification.cpp +++ b/webkit/api/src/WebNotification.cpp @@ -58,6 +58,11 @@ void WebNotification::assign(const WebNotification& other) assign(p); } +bool WebNotification::lessThan(const WebNotification& other) const +{ + return reinterpret_cast<uintptr_t>(m_private) < reinterpret_cast<uintptr_t>(other.m_private); +} + bool WebNotification::isHTML() const { return m_private->isHTML(); @@ -89,19 +94,22 @@ WebString WebNotification::body() const void WebNotification::dispatchDisplayEvent() { - m_private->dispatchDisplayEvent(); + RefPtr<Event> event = Event::create("display", false, true); + m_private->dispatchEvent(event.release()); } void WebNotification::dispatchErrorEvent(const WebKit::WebString& /* errorMessage */) { // FIXME: errorMessage not supported by WebCore yet - m_private->dispatchErrorEvent(); + RefPtr<Event> event = Event::create(eventNames().errorEvent, false, true); + m_private->dispatchEvent(event.release()); } void WebNotification::dispatchCloseEvent(bool /* byUser */) { // FIXME: byUser flag not supported by WebCore yet - m_private->dispatchCloseEvent(); + RefPtr<Event> event = Event::create(eventNames().closeEvent, false, true); + m_private->dispatchEvent(event.release()); } WebNotification::WebNotification(const WTF::PassRefPtr<Notification>& notification) |