Nested native widgets in our content cause much pain. They complicate our life in all sorts of ways ... we have to carefully synchronize their updates, we have to draw into them many times, we get into trouble with z-ordering, etc etc. They also consume system resources, and they're not very compatible with hardware accelerated rendering. In 1.9 it is time to get rid of them as we move to our new graphics infrastructure.
Why do we need native widgets? There are two places where we're really stuck with native widgets:
- Plugins. Enough said.
- Scrolling. In X11 it is difficult to scroll a subarea of an X window smoothly when it contains other X windows unless the area to scroll itself has an X window. Worse, on all platforms, we need plugins to be clipped when they scroll out of view, and that requires a native widget.
We should investigate comprehensive per-platform fixes to encapsulate plugin handling. For example, on modern X servers the COMPOSITE and Damage extensions would let us render a plugin to an offscreen buffer; then we can feed the plugin's display through our rendering pipeline. We'll need this to get plugins working well under SVG transforms. But we won't be able to rely on such mechanisms for a while.
In the meantime, here is a plan for improving the situation:
- Each top-level window has a single native widget root.
- Each plugin in the window gets two native widgets. One for the plugin itself, and one "clipping widget" that is the parent of the plugin widget and is a direct child of the root widget.
- There are no other native widgets.
- Every time content geometry changes in a way that affects the positioning or clipping of a plugin, we reflect that change by repositioning the clipping and plugin widgets and changing the size of the clipping widget.
- To scroll, we do in-window bitblits of the main window and reconfigure the plugin/clipping widgets.
This will require hooking up all viewmanagers in a window into a single tree. Currently view managers in content subshells of chrome shells are not hooked up to their parent.
To scroll a page where the plugins must move, here's how it could work:
- Scroll requests are queued up until we're ready for a repaint
- We figure out which parts of the window will need to be repainted after scrolling has happened and plugins have moved
- That area is rendered to an offscreen buffer
- We perform the scroll operations
- We move each plugin's widget and move/resize its clipping widget
- We copy the backbuffer to the main window
- No more content widgets to worry about
- Greatly reduced usage of native widgets
- Much code removal
- Plugins get clipped properly in all situations where the clip area is rectilinear (currently they don't in some cases), or even to arbitrary regions
- Possibly increased flicker/redrawing when plugins are present, in some cases, but only for windowed, non-encapsulated plugins.
Popup windows (menus and combobox dropdowns) would be handled as toplevel windows.
- Will this be acceptable for plugins?
- How will various platforms cope, especially Cocoa, where scrollbars are native widgets?
- This will cause some problems for accessibility, which currently depends on native widgets being attached to the browser content window, but Aaron thinks he can deal with it.
It looks like Cocoa might be able to paint scrollbars via NSSliderCell.