Some random notes about how I think rendering should work once we've reached the nirvana of one widget per toplevel window with child widgets for plugins only.
Consider two separate cases: 1) scheduled updates: when we request invalidation ourselves 2) unscheduled updates: when the window system asks us to paint
- Accumulate invalid area in a local data structure (like nsViewManager::UpdateWidgetArea does during paint batching).
- Also accumulate scroll requests into a list of "bitblt this region by this offset" requests. When a scroll request is received, update the invalid area appropriately: if we are to scroll region R by delta D, then set I' = I - (R+D) + (R \intersect I)+D. I.e., the currently-invalid area is scrolled the same way. The invariant is that the display will be correct after we apply the bitblt list and then repaint the invalid area.
- Use an animation controller to periodically schedule updates while there is any updating to be done, taking into account desired frame rate, and estimated time Tdraw to draw the next frame.
- When a scheduled update fires:
- Set internal time to now + Tdraw
- Tell SMIL (and JS timers?) to update everything in accordance with the new internal time
- Flush all changes (content, layout reflows) (accumulating more invalidates and scrolls)
- Compute visible area of any plugins
- Call into widget passing the scroll request list, the invalid region, and plugin widget bounds and visible areas
- Widget does the equivalent of setting plugin widget bounds to the new bounds, setting plugin widget visible areas to the new visible areas, performing all scrolls, and repainting the invalid region. If some pixels in scrolled areas are not available or some of the window is exposed by plugin changes, this may require more than the invalid region to be repainted. Platform specific strategies may be used to reduce repainting and/or flicker.
- For example, on Windows, if a plugin's visible area is inside a scrolled area and it is moving by the scroll delta, we may be able to use ScrollWindow options to move the plugin simultaneously with the scroll operation.
- On some platforms we may be able to lock the display while we do all our changes.
- On most platforms, we will win by computing the complete necessary repaint area (or as close an approximation as possible), rendering it to an offscreen buffer, then applying scrolls and updating plugin widgets, then blasting the offscreen buffer onto the screen immediately.
- During this work, Widget calls back to layout one or more times to paint a given region.
- Don't do reflows or update animations. Just paint what we're asked to paint and no more. We may be out of sync a little bit but these unscheduled updates are relatively rare and getting rarer with composited window managers.