Background
Overview
Plugins are a major source of browser crashes. (Flash is in the callstack of a nontrivial percentage of Firefox crashes.) Plugins also make sandboxing the process where the renderer runs impractical, as plugins are written by third-parties and we can't control their access to the operating system. The solution is to run plugins in their own separate process.Detailed design
Plugin interfaces
To run plugins in a separate process, the first step is to separate the code that needs to run in the same process as the plugin from the code that needs to run in the same process as the renderer. TheWebPlugin interface runs in the render process, and WebPluginDelegate is in the plugin process. All communication from the renderer to the plugin, and vice versa, goes through these interfaces.
With these interfaces, simply running plugins in process requires an implementation of WebPlugin, which is our WebPluginImpl class. Similarly, WebPluginDelegateImpl implements the WebPluginDelegate interface. Each object has a pointer to the other interface.
The issues with running plugins in the same process as the renderer are:
- Crashes in the plugin will crash the renderer
- The process can't be sandboxed because the plugin needs access to the operating system
Moving plugins out-of-process
When running plugins in a separate process from the renderer, the WebPluginImpl object lives in the render process, while the WebPluginDelegateImpl is now in a different process (plugin process).
For these two objects to communicate transparently, we use the proxy/stub concept from COM. WebPluginImpl, instead of getting a pointer to WebPluginDelegateImpl, gets a WebPluginDelegateProxy. This object implements the WebPluginDelegate interface, and sends all the function calls over IPC to a corresponding WebPluginDelegateStub in the plugin process. There, WebPluginDelegateStub wraps around a WebPluginDelegateImpl and translates the IPC messages to the actual calls.
Similarly, the WebPluginDelegateImpl gets a WebPluginProxy object, which sends all calls over IPC to a WebPluginStub object in the render process.
Windowless Plugins
To take windowless plugins out of process, you still need to incorporate their rendering in the (synchronous) rendering pass done by WebKit. A naively slow option is to clip out the region that the plugin will draw on then synchronously ship that over to the plugin process and let it draw. This can then be sped up with some shared memory.
However, rendering speed is then at the mercy of the plugin process (imagine a page with 30 transparent plugins -- we'd need 30 round trips to the plugin process). So instead we have windowless plugins asynchronously paint, much like how our existing page rendering is asynchronous with respect to the screen. The renderer has effectively a backing store of what the plugin's rendered area looks like and uses this image when drawing, and the plugin is free to asynchronously send over new updates representing changes to the rendered area.
All of this is complicated a bit by "transparent" plugins. The plugin process needs to know what pixels it wants to draw over. So it also keeps a cache of what the renderer last sent it as the page background behind the plugin, then lets the plugin repeatedly draw over that.
So, in all, here are the buffers involved for the region drawn by a windowless plugin:
Renderer process
- backing store of what the plugin last rendered as
- shared memory with the plugin for receiving updates ("transport DIB")
- copy of the page background behind the plugin (described below)
Plugin process
- copy of the page background behind the plugin, used as the source
material when drawing
- shared memory with the renderer for sending updates ("transport DIB")
Why does the renderer keep a copy of the page background? Because if the page background changes, we need to synchronously get the plugin to redraw over the new background it will appear to lag. We can tell that the background changed by comparing the newly-rendered background against our copy of what the plugin thinks the background. Since the plugin and renderer processes are asynchronous with respect to one another, they need separate copies.

