Gecko:Invalidation: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
 
Line 7: Line 7:
* We need to handle cases like foreignObject where the area to be invalidated must be transformed in interesting ways.
* We need to handle cases like foreignObject where the area to be invalidated must be transformed in interesting ways.


With views, each nsIFrame::Invalidate call pushes a rect up to the nearest ancestor frame with a view. The rect is clipped by the overall clipping applied to the view. It is then added to a region stored on the view, if painting is being batched (which it normally is), or else we go ahead and invalidate widgets immediately. If painting is being batched then widget invalidation is delayed until after paint batching is disabled; we then walk the view tree and take care of any damage regions.
=== Current Status ===


=== Proposal ===
* nsIFrame::Invalidate calls nsIFrame::InvalidateInternal, which is virtual
 
Without views, it's not so clear what we should do. Here's a proposal:
 
* make nsIFrame::Invalidate virtual
* (possibly) add a version that takes an nsRegion and an nsPoint offset
* the standard nsIFrame implementation just computes the offset from this frame to its parent, adds it to rect (or region/offset pair), and calls its parent
* the standard nsIFrame implementation just computes the offset from this frame to its parent, adds it to rect (or region/offset pair), and calls its parent
* nsHTML/XULScrollFrame::Invalidate can clip the invalidation before they pass it up
* nsHTML/XULScrollFrame::InvalidateInternal clips the invalidation before they pass it up
* nsSVGForeignObjectFrame can transform the invalidation and pass it through the SVG invalidation mechanism or just throw it up to the outer SVG frame
* nsSVGForeignObjectFrame transforms the invalidation and pass it through the SVG invalidation mechanism
* Invalidation goes all the way up to the root frame of the root document, where we invalidate widgets. Eventually there will only be one top-level widget to invalidate.
* Invalidation goes all the way up to the root frame of the root document, where we invalidate widgets. Eventually there will only be one top-level widget to invalidate.


=== Invalidation during reflow ===
That's nice and simple, and it doesn't seem to be a problem for performance at the moment, with invalidation batching in place.
 
That's nice and simple, but it could be slow to walk all the way up to the root frame every Invalidate(), especially when we fire lots of invalidates during reflow. I propose to address that by adding fields to the reflow state:
 
    nsIFrame* mInvalidationFrame;
    nsRegion* mInvalidationRegion;
 
These fields are normally inherited, but a frame can set mInvalidationFrame to itself and set mInvalidationRegion to point to an on-stack region before reflowing its children. A frame can invalidate itself more efficiently by computing its offset from mInvalidationFrame and then adding a translated rectangle to mInvalidationRegion. The invalidates will then accumulate in the region and when all descendants have been reflowed, mInvalidationFrame can push up the entire region.
 
An extension would be to say that if mInvalidationFrame is nsnull, then no invalidation needs to be performed (because it's the initial reflow or we know an ancestor frame is going to repaint everything anyway).

Latest revision as of 22:24, 2 January 2007

The Invalidation Problem

Gecko:Invalidation_Handling describes some rules about what should be invalidated, and when. This page is about a separate problem: *how* to implement invalidation, when views have been removed.

  • Invalidation must be fast, because we sometimes invalidate a lot.
  • We'd like to accumulate invalidation in regions, not just take the bounding rect of everything.
  • We need to handle cases like foreignObject where the area to be invalidated must be transformed in interesting ways.

Current Status

  • nsIFrame::Invalidate calls nsIFrame::InvalidateInternal, which is virtual
  • the standard nsIFrame implementation just computes the offset from this frame to its parent, adds it to rect (or region/offset pair), and calls its parent
  • nsHTML/XULScrollFrame::InvalidateInternal clips the invalidation before they pass it up
  • nsSVGForeignObjectFrame transforms the invalidation and pass it through the SVG invalidation mechanism
  • Invalidation goes all the way up to the root frame of the root document, where we invalidate widgets. Eventually there will only be one top-level widget to invalidate.

That's nice and simple, and it doesn't seem to be a problem for performance at the moment, with invalidation batching in place.