Design for desktop notifications

The Desktop Notifications API allows script to request a small toast to appear on the desktop of the user.  The contents of the toast can either be specified as iconUrl/title/text strings, or as a URL to a remote resource which contains the content.

In Chromium/WebKit, the API is provided to scripts in WebCore by injecting into WebKit (via the Chrome/ChromeClient objects) an implementation of a NotificationPresenter interface, which contains methods to show and cancel toasts, as well as to check and request permission to show toasts.  These calls flow via IPC from the renderer process to the browser process, where the toasts are actually created on the screen using a small HtmlView.

Event feedback

Several events flow in the opposite direction: when a notification is displayed (it may not be immediate if the screen is cluttered), closed, or encounters an error, an event is fired which can be listened for by javascript.  These events are detected in the browser process and flow back to the renderer instance which owns the notification object.  Tracking is done by notification-id counters in each renderer process, and a map within the browser process which associates a toast on the screen with the corresponding renderer-process-id and notification-id.  Since the renderer process chooses the id, the IPC involved can be asynchronous.

Lifetime considerations

If a page which is showing a desktop notification is closed, the toast should not be automatically removed from the screen. However, as the javascript Notification object has gone out of scope, Chromium must not attempt to invoke events on it.  The NotificationPresenter interface supports this via a notificationObjectDestroyed() method which must be called from WebCore when a Notification object is destroyed.  

For this reason, the renderer process's NotificationPresenter keeps a map of its notification-id values to Notification object pointers; if a Notification pointer goes out of scope, the NotificationPresenter is called and removes that pointer from the map.  If the browser subsequently calls with an event on that id it will be ignored.

Permissions

Desktop notification permission is assigned on an origin basis.  Chromium stores two PrefLists in the user's profile to accomplish this: OriginsAllowed and OriginsDenied.  A script may request permission on a given origin through a JS API which is routed through the NotificationPresenter interface, into the browser process via IPC, and results in an infobar offering "Allow" or "Deny".  The origin is then stored in the correct PrefList.  

When a notification is to be shown, permission must first be checked: this is handled in the same way, invoking the NotificationPresenter in the renderer, jumping via synchronous IPC to the browser, checking the PrefLists and returning.

Workers' notifications

The same API is available to worker processes and mirrors the behavior for renderers, with IPC messages using a "worker" flag for correct routing of event feedback.

Growl integration

On Mac OS, desktop notifications in icon/title/text format will be routed to Growl for display if Growl is installed (HTML format is not supported yet).  The mechanism is the same as far as the plumbing from renderer->browser->desktop is concerned.  The only difference is that since Growl is invoked from the browser process, the icon is to be downloaded and decoded in a utility process before being passed to Growl as image data.

REMAINING WORK (rough priority)
- Auto-close of notification balloons on a timer
- UI for managing permissions after granting
- UI within the chrome of the toasts allowing permissions changes
- Fade-in/fade-out animations

Browser Process Object Flow
==============
RenderViewHost 
   v  (receives IPC from renderer)
   v
DesktopNotificationService 
   v  (singleton object which handles requests for notifications, also "upcasts" text notification to HTML based on template)
   v
   v  posts a task
   v
NotificationManager
   v   (singleton object on UI thread which manages the space on the desktop for notification balloons)
   v
BalloonCollection 
   v   (set of balloons on the screen, handles animations as balloons are added and removed)
   v
Balloon 
   (mini window, draws notification chrome and contains HTML contents view, receives "dismiss" click from the user)

[on Mac OS, BalloonCollection and below is replaced by Growl framework calls]

Renderer Process Object Flow
==============
Calling from JavaScript to create a notification
NotificationCenter object in WebCore 
   v   (returned by DOMWindow::webkitNotifications()).
   v
   v  V8 bindings
   v
glue::WebNotificationPresenter
   v  (acts as adapter for WebCore::NotificationPresenter interface)
   v
RendererNotificationPresenter 
       (singleton object sends IPC messages to browser, allocates IDs, stores map of ID->Notification objects)

Calling back into JavaScript to relay notification events
RendererNotificationPresenter 
   v   (receives IPC message from browser process regarding an event)
   v
   v (post task onto main thread: lookup in notification-id->Notification object map, discard if invalid)
   v
glue::WebNotification (acts as adapter for WebCore::Notification object)
   v
   v (invoke event listener)
   v
Notification in WebCore