Change the FrameNeedsReflow API to pass the dirty flags to be added directly tothe method, instead of setting them before calling the method. That way we canavoid reflowing the ancestor of a reflow root which is not itself dirty but hasdirty children. This also makes it harder to set dirty bits inconsistentlywith the FrameNeedsReflow call. Bug 378784, r+sr=dbaron, pending rbs' reviewon the mathml parts.
authorbzbarsky@mit.edu
Sun, 06 May 2007 12:16:51 -0700
changeset 1158 b87cba34d6c729e411cd7b0dc23e00d1409ddf5b
parent 1157 b887c3b85aa8c0ab0b47b79267207c5d9613dfd0
child 1159 d514e74fae38ff0e323d420d5c5d6827d4e2a17b
push idunknown
push userunknown
push dateunknown
bugs378784
milestone1.9a5pre
Change the FrameNeedsReflow API to pass the dirty flags to be added directly tothe method, instead of setting them before calling the method. That way we canavoid reflowing the ancestor of a reflow root which is not itself dirty but hasdirty children. This also makes it harder to set dirty bits inconsistentlywith the FrameNeedsReflow call. Bug 378784, r+sr=dbaron, pending rbs' reviewon the mathml parts.
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/forms/nsComboboxControlFrame.cpp
layout/forms/nsFieldSetFrame.cpp
layout/forms/nsHTMLButtonControlFrame.cpp
layout/forms/nsListControlFrame.cpp
layout/generic/nsAbsoluteContainingBlock.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsBulletFrame.cpp
layout/generic/nsColumnSetFrame.cpp
layout/generic/nsContainerFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsHTMLFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsIFrame.h
layout/generic/nsImageFrame.cpp
layout/generic/nsLineLayout.cpp
layout/generic/nsObjectFrame.cpp
layout/generic/nsTextFrame.cpp
layout/generic/nsTextFrameThebes.cpp
layout/generic/nsViewportFrame.cpp
layout/mathml/base/src/nsMathMLContainerFrame.cpp
layout/mathml/base/src/nsMathMLContainerFrame.h
layout/mathml/base/src/nsMathMLmactionFrame.cpp
layout/mathml/base/src/nsMathMLmoFrame.cpp
layout/mathml/base/src/nsMathMLmoverFrame.cpp
layout/mathml/base/src/nsMathMLmstyleFrame.cpp
layout/mathml/base/src/nsMathMLmtableFrame.cpp
layout/mathml/base/src/nsMathMLmunderFrame.cpp
layout/mathml/base/src/nsMathMLmunderoverFrame.cpp
layout/svg/base/src/nsSVGForeignObjectFrame.cpp
layout/svg/base/src/nsSVGOuterSVGFrame.cpp
layout/tables/nsTableColGroupFrame.cpp
layout/tables/nsTableFrame.cpp
layout/tables/nsTableOuterFrame.cpp
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowGroupFrame.cpp
layout/xul/base/src/grid/nsGridRow.cpp
layout/xul/base/src/grid/nsGridRowGroupLayout.cpp
layout/xul/base/src/grid/nsGridRowLeafLayout.cpp
layout/xul/base/src/nsBoxFrame.cpp
layout/xul/base/src/nsImageBoxFrame.cpp
layout/xul/base/src/nsListBoxBodyFrame.cpp
layout/xul/base/src/nsListBoxLayout.cpp
layout/xul/base/src/nsMenuFrame.cpp
layout/xul/base/src/nsPopupSetFrame.cpp
layout/xul/base/src/nsProgressMeterFrame.cpp
layout/xul/base/src/nsSliderFrame.cpp
layout/xul/base/src/nsSplitterFrame.cpp
layout/xul/base/src/nsSprocketLayout.cpp
layout/xul/base/src/nsStackLayout.cpp
layout/xul/base/src/nsTextBoxFrame.cpp
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -9795,18 +9795,18 @@ nsCSSFrameConstructor::StyleChangeReflow
 
   // If the frame is part of a split block-in-inline hierarchy, then
   // target the style-change reflow at the first ``normal'' ancestor
   // so we're sure that the style change will propagate to any
   // anonymously created siblings.
   if (IsFrameSpecial(aFrame))
     aFrame = GetIBContainingBlockFor(aFrame);
 
-  aFrame->AddStateBits(NS_FRAME_IS_DIRTY);
-  mPresShell->FrameNeedsReflow(aFrame, nsIPresShell::eStyleChange);
+  mPresShell->FrameNeedsReflow(aFrame, nsIPresShell::eStyleChange,
+                               NS_FRAME_IS_DIRTY);
 
   return NS_OK;
 }
 
 nsresult
 nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
                                             PRBool aAppend)
 {
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -94,16 +94,17 @@ class nsIStyleSheet;
 class nsCSSFrameConstructor;
 class nsISelection;
 template<class E> class nsCOMArray;
 class nsWeakFrame;
 class nsIScrollableFrame;
 class gfxASurface;
 
 typedef short SelectionType;
+typedef PRUint32 nsFrameState;
 
 // DC543B71-6F1A-4B9F-B4CF-693AEC4BA24A
 #define NS_IPRESSHELL_IID \
 { 0xdc543b71, 0x6f1a, 0x4b9f, \
   { 0xb4, 0xcf, 0x69, 0x3a, 0xec, 0x4b, 0xa2, 0x4a } }
 
 // Constants for ScrollContentIntoView() function
 #define NS_PRESSHELL_SCROLL_TOP      0
@@ -336,29 +337,31 @@ public:
   /**
    * Gets the placeholder frame associated with the specified frame. This is
    * a helper frame that forwards the request to the frame manager.
    */
   NS_IMETHOD GetPlaceholderFrameFor(nsIFrame*  aFrame,
                                     nsIFrame** aPlaceholderFrame) const = 0;
 
   /**
-   * Tell the pres shell that a frame is dirty (as indicated by bits)
-   * and needs Reflow.  It's OK if this is an ancestor of the frame needing
-   * reflow as long as the ancestor chain between them doesn't cross a reflow
-   * root.
+   * Tell the pres shell that a frame needs to be marked dirty and needs
+   * Reflow.  It's OK if this is an ancestor of the frame needing reflow as
+   * long as the ancestor chain between them doesn't cross a reflow root.  The
+   * bits to add should be some combination of NS_FRAME_IS_DIRTY and
+   * NS_FRAME_HAS_DIRTY_CHILDREN.
    */
   enum IntrinsicDirty {
     // XXXldb eResize should be renamed
     eResize,     // don't mark any intrinsic widths dirty
     eTreeChange, // mark intrinsic widths dirty on aFrame and its ancestors
     eStyleChange // Do eTreeChange, plus all of aFrame's descendants
   };
   NS_IMETHOD FrameNeedsReflow(nsIFrame *aFrame,
-                              IntrinsicDirty aIntrinsicDirty) = 0;
+                              IntrinsicDirty aIntrinsicDirty,
+                              nsFrameState aBitsToAdd) = 0;
 
   NS_IMETHOD CancelAllPendingReflows() = 0;
 
   /**
    * Recreates the frames for a node
    */
   NS_IMETHOD RecreateFramesFor(nsIContent* aContent) = 0;
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -807,17 +807,18 @@ public:
   NS_IMETHOD StyleChangeReflow();
   NS_IMETHOD GetPageSequenceFrame(nsIPageSequenceFrame** aResult) const;
   virtual NS_HIDDEN_(nsIFrame*) GetPrimaryFrameFor(nsIContent* aContent) const;
 
   NS_IMETHOD GetLayoutObjectFor(nsIContent*   aContent,
                                 nsISupports** aResult) const;
   NS_IMETHOD GetPlaceholderFrameFor(nsIFrame*  aFrame,
                                     nsIFrame** aPlaceholderFrame) const;
-  NS_IMETHOD FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty);
+  NS_IMETHOD FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
+                              nsFrameState aBitsToAdd);
   NS_IMETHOD CancelAllPendingReflows();
   NS_IMETHOD IsSafeToFlush(PRBool& aIsSafeToFlush);
   NS_IMETHOD FlushPendingNotifications(mozFlushType aType);
 
   /**
    * Recreates the frames for a node
    */
   NS_IMETHOD RecreateFramesFor(nsIContent* aContent);
@@ -2457,19 +2458,28 @@ PresShell::InitialReflow(nscoord aWidth,
     MOZ_TIMER_STOP(mFrameCreationWatch);
 
     // Something in mFrameConstructor->ContentInserted may have caused
     // Destroy() to get called, bug 337586.
     NS_ENSURE_STATE(!mHaveShutDown);
   }
 
   if (rootFrame) {
-    rootFrame->AddStateBits(NS_FRAME_IS_DIRTY);
-    FrameNeedsReflow(rootFrame, eResize);
-    mDirtyRoots.AppendElement(rootFrame);
+    // Note: Because the frame just got created, it has the NS_FRAME_IS_DIRTY
+    // bit set.  Unset it so that FrameNeedsReflow() will work right.
+    NS_ASSERTION(mDirtyRoots.IndexOf(rootFrame) == -1,
+                 "Why is the root in mDirtyRoots already?");
+
+    rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
+                               NS_FRAME_HAS_DIRTY_CHILDREN);
+    FrameNeedsReflow(rootFrame, eResize, NS_FRAME_IS_DIRTY);
+
+    NS_ASSERTION(mDirtyRoots.IndexOf(rootFrame) != -1,
+                 "Should be in mDirtyRoots now");
+    NS_ASSERTION(mReflowEvent.IsPending(), "Why no reflow event pending?");
   }
 
   // Restore our root scroll position now if we're getting here after EndLoad
   // got called, since this is our one chance to do it.  Note that we need not
   // have reflowed for this to work; when the scrollframe is finally reflowed
   // it'll puick up the position we store in it here.
   if (!mDocumentLoading) {
     RestoreRootScrollPosition();
@@ -2927,23 +2937,17 @@ NS_IMETHODIMP
 PresShell::StyleChangeReflow()
 {
   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
   // At the moment at least, we don't have a root frame before the initial
   // reflow; it's safe to just ignore the request in that case
   if (!rootFrame)
     return NS_OK;
 
-  if (!(rootFrame->GetStateBits() &
-        (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
-    rootFrame->AddStateBits(NS_FRAME_IS_DIRTY);
-    mDirtyRoots.AppendElement(rootFrame);
-  }
-
-  return FrameNeedsReflow(rootFrame, eStyleChange);
+  return FrameNeedsReflow(rootFrame, eStyleChange, NS_FRAME_IS_DIRTY);
 }
 
 nsIFrame*
 nsIPresShell::GetRootFrame() const
 {
   return FrameManager()->GetRootFrame();
 }
 
@@ -3104,21 +3108,22 @@ PresShell::VerifyHasDirtyRootAncestor(ns
     aFrame = aFrame->GetParent();
   }
   NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
                 "reflowed?");
 }
 #endif
 
 NS_IMETHODIMP
-PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty)
-{
-  NS_PRECONDITION(aFrame->GetStateBits() &
-                    (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN),
-                  "frame not dirty");
+PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
+                            nsFrameState aBitsToAdd)
+{
+  NS_PRECONDITION(aBitsToAdd == NS_FRAME_IS_DIRTY ||
+                  aBitsToAdd == NS_FRAME_HAS_DIRTY_CHILDREN,
+                  "Unexpected bits being added");
 
   // XXX Add this assertion at some point!?  nsSliderFrame triggers it a lot.
   //NS_ASSERTION(!mIsReflowing, "can't mark frame dirty during reflow");
 
   // If we've not yet done the initial reflow, then don't bother
   // enqueuing a reflow command yet.
   if (! mDidInitialReflow)
     return NS_OK;
@@ -3139,24 +3144,35 @@ PresShell::FrameNeedsReflow(nsIFrame *aF
       nsIContent *rootContent = mDocument->GetRootContent();
       if (rootContent) {
         rootContent->List(stdout, 0);
       }
     }
   }  
 #endif
 
+  // Grab |wasDirty| now so we can go ahead and update the bits on
+  // aFrame and then get |targetFrameDirty|.
+  PRBool wasDirty = NS_SUBTREE_DIRTY(aFrame);
+  aFrame->AddStateBits(aBitsToAdd);
+  PRBool targetFrameDirty = ((aFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0);
+#define FRAME_IS_REFLOW_ROOT(_f)                   \
+  ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) &&  \
+   (_f != aFrame || !targetFrameDirty))
+
+
   // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
   // and all of its descendants, if needed:
 
   if (aIntrinsicDirty != eResize) {
-    // Mark argument and all ancestors dirty (unless we hit a reflow root
-    // other than aFrame)
+    // Mark argument and all ancestors dirty. (Unless we hit a reflow root that
+    // should contain the reflow.  That root could be aFrame itself if it's not
+    // dirty, or it could be some ancestor of aFrame.)
     for (nsIFrame *a = aFrame;
-         a && (!(a->GetStateBits() & NS_FRAME_REFLOW_ROOT) || a == aFrame);
+         a && !FRAME_IS_REFLOW_ROOT(a);
          a = a->GetParent())
       a->MarkIntrinsicWidthsDirty();
   }
 
   if (aIntrinsicDirty == eStyleChange) {
     // Mark all descendants dirty (using an nsVoidArray stack rather than
     // recursion).
     nsVoidArray stack;
@@ -3178,20 +3194,18 @@ PresShell::FrameNeedsReflow(nsIFrame *aF
         }
       } while (childListName);
     }
   }
 
   // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty) up the
   // tree until we reach either a frame that's already dirty or a reflow root.
   nsIFrame *f = aFrame;
-  PRBool wasDirty = PR_TRUE;
   for (;;) {
-    if (((f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && f != aFrame) ||
-        !f->GetParent()) {
+    if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
       // we've hit a reflow root or the root frame
       if (!wasDirty) {
         // Remove existing entries so we don't get duplicates,
         // NotifyDestroyingFrame() only removes one entry, bug 366320.
         while (NS_UNLIKELY(mDirtyRoots.RemoveElement(f))) {
           NS_ERROR("wasDirty lied");
         }
         mDirtyRoots.AppendElement(f);
@@ -3202,18 +3216,17 @@ PresShell::FrameNeedsReflow(nsIFrame *aF
       }
 #endif
       
       break;
     }
 
     nsIFrame *child = f;
     f = f->GetParent();
-    wasDirty = ((f->GetStateBits() & 
-                 (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0);
+    wasDirty = NS_SUBTREE_DIRTY(f);
     f->ChildIsDirty(child);
     NS_ASSERTION(f->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN,
                  "ChildIsDirty didn't do its job");
     if (wasDirty) {
       // This frame was already marked dirty.
 #ifdef DEBUG
       VerifyHasDirtyRootAncestor(f);
 #endif
@@ -6134,18 +6147,17 @@ PresShell::ProcessReflowCommands(PRBool 
       mIsReflowing = PR_TRUE;
 
       do {
         // Send an incremental reflow notification to the target frame.
         PRInt32 idx = mDirtyRoots.Count() - 1;
         nsIFrame *target = NS_STATIC_CAST(nsIFrame*, mDirtyRoots[idx]);
         mDirtyRoots.RemoveElementAt(idx);
 
-        if (!(target->GetStateBits() &
-              (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
+        if (!NS_SUBTREE_DIRTY(target)) {
           // It's not dirty anymore, which probably means the notification
           // was posted in the middle of a reflow (perhaps with a reflow
           // root in the middle).  Don't do anything.
           continue;
         }
 
         DoReflow(target);
 
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -442,18 +442,17 @@ nsComboboxControlFrame::ShowList(nsPresC
 nsresult
 nsComboboxControlFrame::ReflowDropdown(nsPresContext*  aPresContext, 
                                        const nsHTMLReflowState& aReflowState)
 {
   // All we want out of it later on, really, is the height of a row, so we
   // don't even need to cache mDropdownFrame's ascent or anything.  If we don't
   // need to reflow it, just bail out here.
   if (!aReflowState.ShouldReflowAllKids() &&
-      !(mDropdownFrame->GetStateBits() & (NS_FRAME_IS_DIRTY |
-                                          NS_FRAME_HAS_DIRTY_CHILDREN))) {
+      !NS_SUBTREE_DIRTY(mDropdownFrame)) {
     return NS_OK;
   }
 
   // XXXbz this will, for small-height dropdowns, have extra space on the right
   // edge for the scrollbar we don't show... but that's the best we can do here
   // for now.
   nsSize availSize(aReflowState.availableWidth, NS_UNCONSTRAINEDSIZE);
   nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mDropdownFrame,
@@ -823,20 +822,20 @@ nsComboboxControlFrame::HandleRedisplayT
   // Redirect frame insertions during this method (see GetContentInsertionFrame())
   // so that any reframing that the frame constructor forces upon us is inserted
   // into the correct parent (mDisplayFrame). See bug 282607.
   NS_PRECONDITION(!mInRedisplayText, "Nested RedisplayText");
   mInRedisplayText = PR_TRUE;
   mRedisplayTextEvent.Forget();
 
   ActuallyDisplayText(PR_TRUE);
-  mDisplayFrame->AddStateBits(NS_FRAME_IS_DIRTY);
   // XXXbz This should perhaps be eResize.  Check.
   PresContext()->PresShell()->FrameNeedsReflow(mDisplayFrame,
-                                                  nsIPresShell::eStyleChange);
+                                               nsIPresShell::eStyleChange,
+                                               NS_FRAME_IS_DIRTY);
 
   mInRedisplayText = PR_FALSE;
 }
 
 void
 nsComboboxControlFrame::ActuallyDisplayText(PRBool aNotify)
 {
   if (mDisplayedOptionText.IsEmpty()) {
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -454,23 +454,19 @@ nsFieldSetFrame::Reflow(nsPresContext*  
   //------------ Handle Incremental Reflow -----------------
   PRBool reflowContent;
   PRBool reflowLegend;
 
   if (aReflowState.ShouldReflowAllKids()) {
     reflowContent = mContentFrame != nsnull;
     reflowLegend = mLegendFrame != nsnull;
   } else {
-    reflowContent = mContentFrame &&
-      (mContentFrame->GetStateBits() &
-       (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0;
+    reflowContent = mContentFrame && NS_SUBTREE_DIRTY(mContentFrame);
 
-    reflowLegend = mLegendFrame &&
-      (mLegendFrame->GetStateBits() &
-       (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0;
+    reflowLegend = mLegendFrame && NS_SUBTREE_DIRTY(mLegendFrame);
   }
 
   nsSize availSize(aReflowState.ComputedWidth(), aReflowState.availableHeight);
   NS_ASSERTION(!mContentFrame ||
                GetContentMinWidth(aReflowState.rendContext) <= availSize.width,
                "Bogus availSize.width; should be bigger");
 
   // get our border and padding
@@ -694,19 +690,18 @@ nsFieldSetFrame::RemoveFrame(nsIAtom*   
   // For reference, see bug 70648, bug 276104 and bug 236071.
   if (aOldFrame == mLegendFrame) {
     NS_ASSERTION(!aListName, "Unexpected frame list when removing legend frame");
     NS_ASSERTION(mLegendFrame->GetParent() == this, "Legend Parent has wrong parent");
     NS_ASSERTION(mLegendFrame->GetNextSibling() == mContentFrame, "mContentFrame is not next sibling");
 
     mFrames.DestroyFrame(mLegendFrame);
     mLegendFrame = nsnull;
-    AddStateBits(NS_FRAME_IS_DIRTY);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
     return NS_OK;
   }
   return mContentFrame->RemoveFrame(aListName, aOldFrame);
 }
 
 #ifdef ACCESSIBILITY
 NS_IMETHODIMP nsFieldSetFrame::GetAccessible(nsIAccessible** aAccessible)
 {
@@ -724,19 +719,19 @@ nsIFrame*
 nsFieldSetFrame::MaybeSetLegend(nsIFrame* aFrameList, nsIAtom* aListName)
 {
   if (!mLegendFrame && aFrameList->GetType() == nsGkAtoms::legendFrame) {
     NS_ASSERTION(!aListName, "Unexpected frame list when adding legend frame");
     mLegendFrame = aFrameList;
     aFrameList = mLegendFrame->GetNextSibling();
     mLegendFrame->SetNextSibling(mContentFrame);
     mFrames.SetFrames(mLegendFrame);
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN);
   }
   return aFrameList;
 }
 
 void
 nsFieldSetFrame::ReParentFrameList(nsIFrame* aFrameList)
 {
   nsFrameManager* frameManager = PresContext()->FrameManager();
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -288,18 +288,17 @@ nsHTMLButtonControlFrame::Reflow(nsPresC
     nsFormControlFrame::RegUnRegAccessKey(NS_STATIC_CAST(nsIFrame*, this), PR_TRUE);
   }
 
   // Reflow the child
   nsIFrame* firstKid = mFrames.FirstChild();
 
   // XXXbz Eventually we may want to check-and-bail if
   // !aReflowState.ShouldReflowAllKids() &&
-  // !(firstKid->GetStateBits() &
-  //   (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)).
+  // !NS_SUBTREE_DIRTY(firstKid).
   // We'd need to cache our ascent for that, of course.
   
   nsMargin focusPadding = mRenderer.GetAddedButtonBorderAndPadding();
   
   // Reflow the contents of the button.
   ReflowButtonContents(aPresContext, aDesiredSize, aReflowState, firstKid,
                        focusPadding, aStatus);
 
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -562,18 +562,17 @@ nsListControlFrame::Reflow(nsPresContext
    * - We're not dirty and have no dirty kids.  In this case, our cached max
    *   height of a child is not going to change.
    * - We do our first reflow using our cached max height of a child, then
    *   compute the new max height and it's the same as the old one.
    */
 
   PRBool autoHeight = (aReflowState.mComputedHeight == NS_UNCONSTRAINEDSIZE);
 
-  mMightNeedSecondPass = autoHeight &&
-    (GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN));
+  mMightNeedSecondPass = autoHeight && NS_SUBTREE_DIRTY(this);
   
   nsHTMLReflowState state(aReflowState);
   PRInt32 length = GetNumberOfOptions();  
 
   nscoord oldHeightOfARow = HeightOfARow();
   
   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW) && autoHeight) {
     // When not doing an initial reflow, and when the height is auto, start off
@@ -631,18 +630,17 @@ nsresult
 nsListControlFrame::ReflowAsDropdown(nsPresContext*           aPresContext, 
                                      nsHTMLReflowMetrics&     aDesiredSize,
                                      const nsHTMLReflowState& aReflowState, 
                                      nsReflowStatus&          aStatus)
 {
   NS_PRECONDITION(aReflowState.mComputedHeight == NS_UNCONSTRAINEDSIZE,
                   "We should not have a computed height here!");
   
-  mMightNeedSecondPass =
-    (GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0;
+  mMightNeedSecondPass = NS_SUBTREE_DIRTY(this);
 
   nscoord oldHeightOfARow = HeightOfARow();
 
   nsHTMLReflowState state(aReflowState);
 
   nscoord oldVisibleHeight;
   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     // When not doing an initial reflow, and when the height is auto, start off
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -83,21 +83,21 @@ nsAbsoluteContainingBlock::AppendFrames(
   NS_ASSERTION(GetChildListName() == aListName, "unexpected child list");
 
   // Append the frames to our list of absolutely positioned frames
 #ifdef NS_DEBUG
   nsFrame::VerifyDirtyBitSet(aFrameList);
 #endif
   mAbsoluteFrames.AppendFrames(nsnull, aFrameList);
 
-  aDelegatingFrame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   // no damage to intrinsic widths, since absolutely positioned frames can't
   // change them
   return aDelegatingFrame->PresContext()->PresShell()->
-    FrameNeedsReflow(aDelegatingFrame, nsIPresShell::eResize);
+    FrameNeedsReflow(aDelegatingFrame, nsIPresShell::eResize,
+                     NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
 nsresult
 nsAbsoluteContainingBlock::InsertFrames(nsIFrame*      aDelegatingFrame,
                                         nsIAtom*       aListName,
                                         nsIFrame*      aPrevFrame,
                                         nsIFrame*      aFrameList)
 {
@@ -105,21 +105,21 @@ nsAbsoluteContainingBlock::InsertFrames(
   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == aDelegatingFrame,
                "inserting after sibling frame with different parent");
 
 #ifdef NS_DEBUG
   nsFrame::VerifyDirtyBitSet(aFrameList);
 #endif
   mAbsoluteFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
 
-  aDelegatingFrame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   // no damage to intrinsic widths, since absolutely positioned frames can't
   // change them
   return aDelegatingFrame->PresContext()->PresShell()->
-    FrameNeedsReflow(aDelegatingFrame, nsIPresShell::eResize);
+    FrameNeedsReflow(aDelegatingFrame, nsIPresShell::eResize,
+                     NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
 nsresult
 nsAbsoluteContainingBlock::RemoveFrame(nsIFrame*       aDelegatingFrame,
                                        nsIAtom*        aListName,
                                        nsIFrame*       aOldFrame)
 {
   NS_ASSERTION(GetChildListName() == aListName, "unexpected child list");
@@ -165,18 +165,17 @@ nsAbsoluteContainingBlock::Reflow(nsIFra
   if (aChildBounds)
     aChildBounds->SetRect(0, 0, 0, 0);
 
   PRBool reflowAll = aReflowState.ShouldReflowAllKids();
 
   nsIFrame* kidFrame;
   for (kidFrame = mAbsoluteFrames.FirstChild(); kidFrame; kidFrame = kidFrame->GetNextSibling()) {
     if (reflowAll ||
-        (kidFrame->GetStateBits() &
-           (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) ||
+        NS_SUBTREE_DIRTY(kidFrame) ||
         FrameDependsOnContainer(kidFrame, aCBWidthChanged, aCBHeightChanged)) {
       // Reflow the frame
       nsReflowStatus  kidStatus;
       ReflowAbsoluteFrame(aDelegatingFrame, aPresContext, aReflowState, aContainingBlockWidth,
                           aContainingBlockHeight, kidFrame, kidStatus);
 
     }
     AddFrameToChildBounds(kidFrame, aChildBounds);
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -512,19 +512,17 @@ nsBlockFrame::InvalidateInternal(const n
   }
 
   nsBlockFrameSuper::InvalidateInternal(aDamageRect, aX, aY, this, aImmediate);
 }
 
 nscoord
 nsBlockFrame::GetBaseline() const
 {
-  NS_ASSERTION(!(GetStateBits() & (NS_FRAME_IS_DIRTY |
-                                   NS_FRAME_HAS_DIRTY_CHILDREN)),
-               "frame must not be dirty");
+  NS_ASSERTION(!NS_SUBTREE_DIRTY(this), "frame must not be dirty");
   nscoord result;
   if (nsLayoutUtils::GetLastLineBaseline(this, &result))
     return result;
   return nsFrame::GetBaseline();
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Child frame enumeration
@@ -885,17 +883,19 @@ nsBlockFrame::Reflow(nsPresContext*     
         bidiUtils->Resolve(aPresContext, this,
                            mLines.front()->mFirstChild,
                            IsVisualFormControl(aPresContext));
       }
     }
   }
 #endif // IBMBIDI
 
-  RenumberLists(aPresContext);
+  if (RenumberLists(aPresContext)) {
+    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
+  }
 
   nsresult rv = NS_OK;
 
   // ALWAYS drain overflow. We never want to leave the previnflow's
   // overflow lines hanging around; block reflow depends on the
   // overflow line lists being cleared out between reflow passes.
   DrainOverflowLines(state);
   state.SetupOverflowPlaceholdersProperty();
@@ -2423,39 +2423,41 @@ nsBlockFrame::AttributeChanged(PRInt32  
 
   if (NS_FAILED(rv)) {
     return rv;
   }
   if (nsGkAtoms::start == aAttribute) {
     nsPresContext* presContext = PresContext();
 
     // XXX Not sure if this is necessary anymore
-    RenumberLists(presContext);
-
-    presContext->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+    if (RenumberLists(presContext)) {
+      presContext->PresShell()->
+        FrameNeedsReflow(this, nsIPresShell::eStyleChange,
+                         NS_FRAME_HAS_DIRTY_CHILDREN);
+    }
   }
   else if (nsGkAtoms::value == aAttribute) {
     const nsStyleDisplay* styleDisplay = GetStyleDisplay();
     if (NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) {
       // Search for the closest ancestor that's a block frame. We
       // make the assumption that all related list items share a
       // common block parent.
       // XXXldb I think that's a bad assumption.
       nsBlockFrame* blockParent = nsLayoutUtils::FindNearestBlockAncestor(this);
 
       // Tell the enclosing block frame to renumber list items within
       // itself
       if (nsnull != blockParent) {
         nsPresContext* presContext = PresContext();
         // XXX Not sure if this is necessary anymore
-        blockParent->RenumberLists(presContext);
-
-        presContext->PresShell()->
-          FrameNeedsReflow(blockParent, nsIPresShell::eStyleChange);
+        if (blockParent->RenumberLists(presContext)) {
+          presContext->PresShell()->
+            FrameNeedsReflow(blockParent, nsIPresShell::eStyleChange,
+                             NS_FRAME_HAS_DIRTY_CHILDREN);
+        }
       }
     }
   }
 
   return rv;
 }
 
 inline PRBool
@@ -4573,19 +4575,19 @@ nsBlockFrame::AppendFrames(nsIAtom*  aLi
   if (lastKid) {
     printf(" after ");
     nsFrame::ListTag(stdout, lastKid);
   }
   printf("\n");
 #endif
   nsresult rv = AddFrames(aFrameList, lastKid);
   if (NS_SUCCEEDED(rv)) {
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsBlockFrame::InsertFrames(nsIAtom*  aListName,
                            nsIFrame* aPrevFrame,
                            nsIFrame* aFrameList)
@@ -4621,19 +4623,19 @@ nsBlockFrame::InsertFrames(nsIAtom*  aLi
   }
   printf("\n");
 #endif
   nsresult rv = AddFrames(aFrameList, aPrevFrame);
 #ifdef IBMBIDI
   if (aListName != nsGkAtoms::nextBidi)
 #endif // IBMBIDI
   if (NS_SUCCEEDED(rv)) {
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
   }
   return rv;
 }
 
 static PRBool
 ShouldPutNextSiblingOnNewLine(nsIFrame* aLastFrame)
 {
   nsIAtom* type = aLastFrame->GetType();
@@ -4896,19 +4898,19 @@ nsBlockFrame::RemoveFrame(nsIAtom*  aLis
   }
 #endif // IBMBIDI
   else {
     NS_ERROR("unexpected child list");
     rv = NS_ERROR_INVALID_ARG;
   }
 
   if (NS_SUCCEEDED(rv)) {
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
   }
   return rv;
 }
 
 void
 nsBlockFrame::DoRemoveOutOfFlowFrame(nsIFrame* aFrame)
 {
   // First remove aFrame's next in flow
@@ -6033,23 +6035,23 @@ nsBlockFrame::FrameStartsCounterScope(ns
 
   nsIAtom *localName = content->NodeInfo()->NameAtom();
   return localName == nsGkAtoms::ol ||
          localName == nsGkAtoms::ul ||
          localName == nsGkAtoms::dir ||
          localName == nsGkAtoms::menu;
 }
 
-void
+PRBool
 nsBlockFrame::RenumberLists(nsPresContext* aPresContext)
 {
   if (!FrameStartsCounterScope(this)) {
     // If this frame doesn't start a counter scope then we don't need
     // to renumber child list items.
-    return;
+    return PR_FALSE;
   }
 
   // Setup initial list ordinal value
   // XXX Map html's start property to counter-reset style
   PRInt32 ordinal = 1;
 
   nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
 
@@ -6057,18 +6059,17 @@ nsBlockFrame::RenumberLists(nsPresContex
     const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::start);
     if (attr && attr->Type() == nsAttrValue::eInteger) {
       ordinal = attr->GetIntegerValue();
     }
   }
 
   // Get to first-in-flow
   nsBlockFrame* block = (nsBlockFrame*) GetFirstInFlow();
-  if (RenumberListsInBlock(aPresContext, block, &ordinal, 0))
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
+  return RenumberListsInBlock(aPresContext, block, &ordinal, 0);
 }
 
 PRBool
 nsBlockFrame::RenumberListsInBlock(nsPresContext* aPresContext,
                                    nsBlockFrame* aBlockFrame,
                                    PRInt32* aOrdinal,
                                    PRInt32 aDepth)
 {
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -517,17 +517,21 @@ protected:
                             nsLineBox* aLine,
                             nscoord aDeltaY);
 
   void CheckFloats(nsBlockReflowState& aState);
 
   //----------------------------------------
   // List handling kludge
 
-  void RenumberLists(nsPresContext* aPresContext);
+  // If this returns PR_TRUE, the block it's called on should get the
+  // NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
+  // if it's already in reflow, or via calling FrameNeedsReflow() to schedule a
+  // reflow.
+  PRBool RenumberLists(nsPresContext* aPresContext);
 
   PRBool RenumberListsInBlock(nsPresContext* aPresContext,
                               nsBlockFrame* aContainerFrame,
                               PRInt32* aOrdinal,
                               PRInt32 aDepth);
 
   PRBool RenumberListsFor(nsPresContext* aPresContext, nsIFrame* aKid, PRInt32* aOrdinal, PRInt32 aDepth);
 
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -1610,21 +1610,18 @@ NS_IMETHODIMP nsBulletFrame::OnStartCont
 
   if (mIntrinsicSize != newsize) {
     mIntrinsicSize = newsize;
 
     // Now that the size is available (or an error occurred), trigger
     // a reflow of the bullet frame.
     nsIPresShell *shell = presContext->GetPresShell();
     if (shell) {
-      NS_ASSERTION(mParent, "No parent to pass the reflow request up to.");
-      if (mParent) {
-        mState |= NS_FRAME_IS_DIRTY;
-        shell->FrameNeedsReflow(this, nsIPresShell::eStyleChange);
-      }
+      shell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
+                              NS_FRAME_IS_DIRTY);
     }
   }
 
   // Handle animations
   aImage->SetAnimationMode(presContext->ImageAnimationMode());
   // Ensure the animation (if any) is started.
   aImage->StartAnimation();
 
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -330,17 +330,17 @@ PRBool
 nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&     aDesiredSize,
                                  const nsHTMLReflowState& aReflowState,
                                  nsReflowStatus&          aStatus,
                                  const ReflowConfig&      aConfig,
                                  PRBool                   aUnboundedLastColumn,
                                  nsCollapsingMargin*      aBottomMarginCarriedOut) {
   PRBool allFit = PR_TRUE;
   PRBool RTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
-  PRBool shrinkingHeightOnly = !(GetStateBits() & (NS_FRAME_IS_DIRTY|NS_FRAME_HAS_DIRTY_CHILDREN)) &&
+  PRBool shrinkingHeightOnly = !NS_SUBTREE_DIRTY(this) &&
     mLastBalanceHeight > aConfig.mColMaxHeight;
   
 #ifdef DEBUG_roc
   printf("*** Doing column reflow pass: mLastBalanceHeight=%d, mColMaxHeight=%d, RTL=%d\n, mBalanceColCount=%d, mColWidth=%d, mColGap=%d\n",
          mLastBalanceHeight, aConfig.mColMaxHeight, RTL, aConfig.mBalanceColCount,
          aConfig.mColWidth, aConfig.mColGap);
 #endif
 
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -133,19 +133,18 @@ nsContainerFrame::AppendFrames(nsIAtom* 
   if (aFrameList) {
     mFrames.AppendFrames(this, aFrameList);
 
     // Ask the parent frame to reflow me.
 #ifdef IBMBIDI
     if (nsnull == aListName)
 #endif
     {
-      AddStateBits(NS_FRAME_IS_DIRTY);
       PresContext()->PresShell()->
-        FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+        FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContainerFrame::InsertFrames(nsIAtom*  aListName,
                                nsIFrame* aPrevFrame,
@@ -166,20 +165,18 @@ nsContainerFrame::InsertFrames(nsIAtom* 
   if (aFrameList) {
     // Insert frames after aPrevFrame
     mFrames.InsertFrames(this, aPrevFrame, aFrameList);
 
 #ifdef IBMBIDI
     if (nsnull == aListName)
 #endif
     {
-      // Ask the parent frame to reflow me.
-      AddStateBits(NS_FRAME_IS_DIRTY);
       PresContext()->PresShell()->
-        FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+        FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContainerFrame::RemoveFrame(nsIAtom*  aListName,
                               nsIFrame* aOldFrame)
@@ -224,20 +221,18 @@ nsContainerFrame::RemoveFrame(nsIAtom*  
       parent->mFrames.DestroyFrame(aOldFrame);
       aOldFrame = oldFrameNextContinuation;
       if (aOldFrame) {
         parent = NS_STATIC_CAST(nsContainerFrame*, aOldFrame->GetParent());
       }
     }
 
     if (generateReflowCommand) {
-      // Ask the parent frame to reflow me.
-      AddStateBits(NS_FRAME_IS_DIRTY);
       PresContext()->PresShell()->
-        FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+        FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
     }
   }
 
   return NS_OK;
 }
 
 void
 nsContainerFrame::CleanupGeneratedContentIn(nsIContent* aRealContent,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -683,18 +683,17 @@ nsFrame::GetOffsets(PRInt32 &aStart, PRI
 NS_IMETHODIMP nsFrame::DidSetStyleContext()
 {
   return NS_OK;
 }
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedMargin() const
 {
-  NS_ASSERTION(!(GetStateBits() &
-                 (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) ||
+  NS_ASSERTION(!NS_SUBTREE_DIRTY(this) ||
                (GetStateBits() & NS_FRAME_IN_REFLOW),
                "cannot call on a dirty frame not currently being reflowed");
 
   nsMargin margin(0, 0, 0, 0);
   if (!GetStyleMargin()->GetMargin(margin)) {
     nsMargin *m = NS_STATIC_CAST(nsMargin*,
                     GetProperty(nsGkAtoms::usedMarginProperty));
     NS_ASSERTION(m, "used margin property missing (out of memory?)");
@@ -703,18 +702,17 @@ nsIFrame::GetUsedMargin() const
     }
   }
   return margin;
 }
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedBorder() const
 {
-  NS_ASSERTION(!(GetStateBits() &
-                 (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) ||
+  NS_ASSERTION(!NS_SUBTREE_DIRTY(this) ||
                (GetStateBits() & NS_FRAME_IN_REFLOW),
                "cannot call on a dirty frame not currently being reflowed");
 
   // Theme methods don't use const-ness.
   nsIFrame *mutable_this = NS_CONST_CAST(nsIFrame*, this);
 
   const nsStyleDisplay *disp = GetStyleDisplay();
   if (mutable_this->IsThemed(disp)) {
@@ -731,18 +729,17 @@ nsIFrame::GetUsedBorder() const
   }
 
   return GetStyleBorder()->GetBorder();
 }
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedPadding() const
 {
-  NS_ASSERTION(!(GetStateBits() &
-                 (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) ||
+  NS_ASSERTION(!NS_SUBTREE_DIRTY(this) ||
                (GetStateBits() & NS_FRAME_IN_REFLOW),
                "cannot call on a dirty frame not currently being reflowed");
 
   nsMargin padding(0, 0, 0, 0);
 
   // Theme methods don't use const-ness.
   nsIFrame *mutable_this = NS_CONST_CAST(nsIFrame*, this);
 
@@ -827,18 +824,17 @@ nsFrame::SetAdditionalStyleContext(PRInt
                                    nsStyleContext* aStyleContext)
 {
   NS_PRECONDITION(aIndex >= 0, "invalid index number");
 }
 
 nscoord
 nsFrame::GetBaseline() const
 {
-  NS_ASSERTION(!(GetStateBits() & (NS_FRAME_IS_DIRTY |
-                                   NS_FRAME_HAS_DIRTY_CHILDREN)),
+  NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
                "frame must not be dirty");
   // Default to the bottom margin edge, per CSS2.1's definition of the
   // 'baseline' value of 'vertical-align'.
   return mRect.height + GetUsedMargin().bottom;
 }
 
 // Child frame enumeration
 
@@ -6108,18 +6104,17 @@ nsFrame::BoxReflow(nsBoxLayoutState&    
   */
 
   nsBoxLayoutMetrics *metrics = BoxMetrics();
   nsReflowStatus status = NS_FRAME_COMPLETE;
 
   PRBool redrawAfterReflow = PR_FALSE;
   PRBool redrawNow = PR_FALSE;
 
-  PRBool needsReflow =
-    (GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0;
+  PRBool needsReflow = NS_SUBTREE_DIRTY(this);
 
   if (redrawNow)
      Redraw(aState);
 
   // if we don't need a reflow then 
   // lets see if we are already that size. Yes? then don't even reflow. We are done.
   if (!needsReflow) {
       
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -729,19 +729,17 @@ nsHTMLScrollFrame::Reflow(nsPresContext*
 
   //------------ Handle Incremental Reflow -----------------
   PRBool reflowContents = PR_TRUE; // XXX Ignored
   PRBool reflowHScrollbar = PR_TRUE;
   PRBool reflowVScrollbar = PR_TRUE;
   PRBool reflowScrollCorner = PR_TRUE;
   if (!aReflowState.ShouldReflowAllKids()) {
     #define NEEDS_REFLOW(frame_) \
-      ((frame_) && \
-       ((frame_)->GetStateBits() & \
-        (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0)
+      ((frame_) && NS_SUBTREE_DIRTY(frame_))
 
     reflowContents = NEEDS_REFLOW(mInner.mScrolledFrame);
     reflowHScrollbar = NEEDS_REFLOW(mInner.mHScrollbarBox);
     reflowVScrollbar = NEEDS_REFLOW(mInner.mVScrollbarBox);
     reflowScrollCorner = NEEDS_REFLOW(mInner.mScrollCornerBox);
 
     #undef NEEDS_REFLOW
   }
@@ -2483,20 +2481,20 @@ nsGfxScrollFrameInner::LayoutScrollbars(
   if (aOldScrollArea.Size() != aScrollArea.Size() && 
       !(mOuter->GetStateBits() & NS_FRAME_IS_DIRTY) &&
       mIsRoot) {
     nsIFrame* parentFrame = mOuter->GetParent();
     for (nsIFrame *fixedChild =
            parentFrame->GetFirstChild(nsGkAtoms::fixedList);
          fixedChild; fixedChild = fixedChild->GetNextSibling()) {
       // force a reflow of the fixed child
-      fixedChild->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
       // XXX Will this work given where we currently are in reflow?
       aState.PresContext()->PresShell()->
-        FrameNeedsReflow(fixedChild, nsIPresShell::eResize);
+        FrameNeedsReflow(fixedChild, nsIPresShell::eResize,
+                         NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
   
   // post reflow callback to modify scrollbar attributes
   if (!mPostedReflowCallback) {
     aState.PresContext()->PresShell()->PostReflowCallback(this);
     mPostedReflowCallback = PR_TRUE;
   }
--- a/layout/generic/nsHTMLFrame.cpp
+++ b/layout/generic/nsHTMLFrame.cpp
@@ -277,17 +277,18 @@ CanvasFrame::AppendFrames(nsIAtom*      
   } else {
     // Insert the new frames
 #ifdef NS_DEBUG
     nsFrame::VerifyDirtyBitSet(aFrameList);
 #endif
     mFrames.AppendFrame(nsnull, aFrameList);
 
     rv = PresContext()->PresShell()->
-           FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+           FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                            NS_FRAME_HAS_DIRTY_CHILDREN);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 CanvasFrame::InsertFrames(nsIAtom*        aListName,
                           nsIFrame*       aPrevFrame,
@@ -323,19 +324,19 @@ CanvasFrame::RemoveFrame(nsIAtom*       
     // Damage the area occupied by the deleted frame
     // The child of the canvas probably can't have an outline, but why bother
     // thinking about that?
     Invalidate(aOldFrame->GetOverflowRect() + aOldFrame->GetPosition(), PR_FALSE);
 
     // Remove the frame and destroy it
     mFrames.DestroyFrame(aOldFrame);
 
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     rv = PresContext()->PresShell()->
-           FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+           FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                            NS_FRAME_HAS_DIRTY_CHILDREN);
   } else {
     rv = NS_ERROR_FAILURE;
   }
 
   return rv;
 }
 
 nsRect CanvasFrame::CanvasArea() const
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -137,18 +137,17 @@ nsHTMLReflowState::nsHTMLReflowState(nsP
   NS_PRECONDITION(aPresContext, "no pres context");
   NS_PRECONDITION(aFrame, "no frame");
   NS_PRECONDITION((aContainingBlockWidth == -1) ==
                     (aContainingBlockHeight == -1),
                   "cb width and height should only be non-default together");
   NS_PRECONDITION(aInit == PR_TRUE || aInit == PR_FALSE,
                   "aInit out of range for PRBool");
   NS_PRECONDITION(!mFlags.mSpecialHeightReflow ||
-                  !(aFrame->GetStateBits() & (NS_FRAME_IS_DIRTY |
-                                              NS_FRAME_HAS_DIRTY_CHILDREN)),
+                  !NS_SUBTREE_DIRTY(aFrame),
                   "frame should be clean when getting special height reflow");
 
   parentReflowState = &aParentReflowState;
 
   // If the parent is dirty, then the child is as well.
   // XXX Are the other cases where the parent reflows a child a second
   // time, as a resize?
   if (!mFlags.mSpecialHeightReflow)
@@ -334,19 +333,17 @@ nsHTMLReflowState::InitResizeFlags(nsPre
     // as containing block for absolutely positioned elements?
     mFlags.mVResize = mCBReflowState->mFlags.mVResize;
   } else if (mComputedHeight == NS_AUTOHEIGHT) {
     if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
         mCBReflowState) {
       // XXX This condition doesn't quite match CalcQuirkContainingBlockHeight.
       mFlags.mVResize = mCBReflowState->mFlags.mVResize;
     } else {
-      mFlags.mVResize = mFlags.mHResize || 
-                        (frame->GetStateBits() &
-                         (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN));
+      mFlags.mVResize = mFlags.mHResize || NS_SUBTREE_DIRTY(frame); 
     }
   } else {
     // not 'auto' height
     mFlags.mVResize = frame->GetSize().height !=
                         mComputedHeight + mComputedBorderPadding.TopBottom();
   }
 
   // It would be nice to check that |mComputedHeight != NS_AUTOHEIGHT|
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -182,29 +182,33 @@ typedef PRUint32 nsFrameState;
 
 // If this bit is set, then the frame reflects content that may be selected
 #define NS_FRAME_SELECTED_CONTENT                     0x00000200
 
 // If this bit is set, then the frame is dirty and needs to be reflowed.
 // This bit is set when the frame is first created.
 // This bit is cleared by DidReflow after the required call to Reflow has
 // finished.
+// Do not set this bit yourself if you plan to pass the frame to
+// nsIPresShell::FrameNeedsReflow.  Pass the right arguments instead.
 #define NS_FRAME_IS_DIRTY                             0x00000400
 
 // If this bit is set then the frame is unflowable.
 #define NS_FRAME_IS_UNFLOWABLE                        0x00000800
 
 // If this bit is set, either:
 //  1. the frame has children that have either NS_FRAME_IS_DIRTY or
 //     NS_FRAME_HAS_DIRTY_CHILDREN, or
 //  2. the frame has had descendants removed.
 // It means that Reflow needs to be called, but that Reflow will not
 // do as much work as it would if NS_FRAME_IS_DIRTY were set.
 // This bit is cleared by DidReflow after the required call to Reflow has
 // finished.
+// Do not set this bit yourself if you plan to pass the frame to
+// nsIPresShell::FrameNeedsReflow.  Pass the right arguments instead.
 #define NS_FRAME_HAS_DIRTY_CHILDREN                   0x00001000
 
 // If this bit is set, the frame has an associated view
 #define NS_FRAME_HAS_VIEW                             0x00002000
 
 // If this bit is set, the frame was created from anonymous content.
 #define NS_FRAME_INDEPENDENT_SELECTION                0x00004000
 
@@ -239,16 +243,21 @@ typedef PRUint32 nsFrameState;
 // The upper 12 bits of the frame state word are reserved for frame
 // implementations.
 #define NS_FRAME_IMPL_RESERVED                        0xFFF00000
 
 // Box layout bits
 #define NS_STATE_IS_HORIZONTAL                        0x00400000
 #define NS_STATE_IS_DIRECTION_NORMAL                  0x80000000
 
+// Helper macros
+#define NS_SUBTREE_DIRTY(_frame)  \
+  (((_frame)->GetStateBits() &      \
+    (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0)
+
 //----------------------------------------------------------------------
 
 enum nsSelectionAmount {
   eSelectCharacter = 0,
   eSelectWord      = 1,
   eSelectLine      = 2,  //previous drawn line in flow.
   eSelectBeginLine = 3,
   eSelectEndLine   = 4,
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -527,22 +527,20 @@ nsImageFrame::OnStartContainer(imgIReque
   }
   
   UpdateIntrinsicSize(aImage);
 
   // Now we need to reflow if we have an unconstrained size and have
   // already gotten the initial reflow
   if (!(mState & IMAGE_SIZECONSTRAINED) && (mState & IMAGE_GOTINITIALREFLOW)) { 
     nsIPresShell *presShell = presContext->GetPresShell();
-    NS_ASSERTION(mParent, "No parent to pass the reflow request up to.");
     NS_ASSERTION(presShell, "No PresShell.");
-    if (mParent && presShell) { 
-      AddStateBits(NS_FRAME_IS_DIRTY);
-      presShell->FrameNeedsReflow(NS_STATIC_CAST(nsIFrame*, this),
-                                  nsIPresShell::eStyleChange);
+    if (presShell) { 
+      presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
+                                  NS_FRAME_IS_DIRTY);
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
@@ -635,21 +633,19 @@ nsImageFrame::OnStopDecode(imgIRequest *
     }
     else {
       // Have to size to 0,0 so that GetDesiredSize recalculates the size
       mIntrinsicSize.SizeTo(0, 0);
     }
 
     if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet
       if (!(mState & IMAGE_SIZECONSTRAINED) && intrinsicSizeChanged) {
-        NS_ASSERTION(mParent, "No parent to pass the reflow request up to.");
-        if (mParent && presShell) { 
-          AddStateBits(NS_FRAME_IS_DIRTY);
-          presShell->FrameNeedsReflow(NS_STATIC_CAST(nsIFrame*, this),
-                                      nsIPresShell::eStyleChange);
+        if (presShell) { 
+          presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
+                                      NS_FRAME_IS_DIRTY);
         }
       } else {
         nsSize s = GetSize();
         nsRect r(0, 0, s.width, s.height);
         // Update border+content to account for image change
         Invalidate(r, PR_FALSE);
       }
     }
@@ -1572,20 +1568,19 @@ nsImageFrame::AttributeChanged(PRInt32 a
 {
   nsresult rv = nsSplittableFrame::AttributeChanged(aNameSpaceID,
                                                     aAttribute, aModType);
   if (NS_FAILED(rv)) {
     return rv;
   }
   if (nsGkAtoms::alt == aAttribute)
   {
-    AddStateBits(NS_FRAME_IS_DIRTY);
-    PresContext()->PresShell()->FrameNeedsReflow(
-                                       NS_STATIC_CAST(nsIFrame*, this),
-                                       nsIPresShell::eStyleChange);
+    PresContext()->PresShell()->FrameNeedsReflow(this,
+                                                 nsIPresShell::eStyleChange,
+                                                 NS_FRAME_IS_DIRTY);
   }
 
   return NS_OK;
 }
 
 nsIAtom*
 nsImageFrame::GetType() const
 {
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -909,18 +909,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
   PRBool placedFloat = PR_FALSE;
   if (frameType) {
     if (nsGkAtoms::placeholderFrame == frameType) {
       pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, PR_TRUE);
       nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame);
       if (outOfFlowFrame) {
         nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, aFrame);
         // XXXldb What is this test supposed to be?
-        if (!(aFrame->GetStateBits() &
-              (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
+        if (!NS_SUBTREE_DIRTY(aFrame)) {
           // incremental reflow of child
           placedFloat = InitFloat(placeholder, aReflowStatus);
         }
         else {
           placedFloat = AddFloat(placeholder, aReflowStatus);
         }
         if (!placedFloat) {
           aReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -750,19 +750,18 @@ nsObjectFrame::InstantiatePlugin(nsIPlug
 #endif
 
   if (appShell) {
     appShell->ResumeNative();
   }
 
   // XXX having to do this sucks. it'd be better to move the code from DidReflow
   // to FixupWindow or something.
-  AddStateBits(NS_FRAME_IS_DIRTY);
   PresContext()->GetPresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+    FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
   return rv;
 }
 
 void
 nsObjectFrame::FixupWindow(const nsSize& aSize)
 {
   nsPresContext* presContext = PresContext();
 
@@ -1316,17 +1315,17 @@ nsObjectFrame::Instantiate(nsIChannel* a
   // This must be done before instantiating the plugin
   FixupWindow(mRect.Size());
 
   rv = pluginHost->InstantiatePluginForChannel(aChannel, mInstanceOwner, aStreamListener);
 
   // XXX having to do this sucks. it'd be better to move the code from DidReflow
   // to FixupWindow.
   PresContext()->GetPresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+    FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
   return rv;
 }
 
 nsresult
 nsObjectFrame::Instantiate(const char* aMimeType, nsIURI* aURI)
 {
   NS_ASSERTION(aMimeType || aURI, "Need a type or a URI!");
   nsresult rv = PrepareInstanceOwner();
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1941,42 +1941,44 @@ nsTextFrame::GetLastContinuation() const
 
 NS_IMETHODIMP
 nsTextFrame::CharacterDataChanged(nsPresContext* aPresContext,
                                   nsIContent*     aChild,
                                   PRBool          aAppend)
 {
   nsIFrame* targetTextFrame = this;
 
-  PRBool markAllDirty = PR_TRUE;
   if (aAppend) {
-    markAllDirty = PR_FALSE;
-    nsTextFrame* frame = NS_STATIC_CAST(nsTextFrame*, GetLastInFlow());
+    nsTextFrame* frame = NS_STATIC_CAST(nsTextFrame*, GetLastContinuation());
     frame->mState &= ~TEXT_WHITESPACE_FLAGS;
-    frame->mState |= NS_FRAME_IS_DIRTY;
     targetTextFrame = frame;
-  }
-
-  if (markAllDirty) {
+  } else {
     // Mark this frame and all the next-in-flow frames as dirty and reset all
     // the content offsets and lengths to 0, since they no longer know what
     // content is ok to access.
+
+    // Don't set NS_FRAME_IS_DIRTY on |this|, since we call FrameNeedsReflow
+    // below.
     nsTextFrame*  textFrame = this;
-    while (textFrame) {
+    do {
       textFrame->mState &= ~TEXT_WHITESPACE_FLAGS;
-      textFrame->mState |= NS_FRAME_IS_DIRTY;
       textFrame->mContentOffset = 0;
       textFrame->mContentLength = 0;
       textFrame = NS_STATIC_CAST(nsTextFrame*, textFrame->GetNextContinuation());
-    }
+      if (!textFrame) {
+        break;
+      }
+      textFrame->mState |= NS_FRAME_IS_DIRTY;
+    } while (1);
   }
 
   // Ask the parent frame to reflow me.  
   aPresContext->GetPresShell()->FrameNeedsReflow(targetTextFrame,
-                                                 nsIPresShell::eStyleChange);
+                                                 nsIPresShell::eStyleChange,
+                                                 NS_FRAME_IS_DIRTY);
 
   return NS_OK;
 }
 
 // When we fix nsTextFrame to handle bearing (character glyphs that
 // extend outside the frame) by giving it overflow area, we'll need to fix
 // this to use the overflow area as its bounds.
 class nsDisplayText : public nsDisplayItem {
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -3088,40 +3088,45 @@ nsTextFrame::CharacterDataChanged(nsPres
 
   nsTextFrame* targetTextFrame;
   nsTextFrame* lastTextFrame;
   PRInt32 nodeLength = mContent->GetText()->GetLength();
 
   if (aAppend) {
     lastTextFrame = NS_STATIC_CAST(nsTextFrame*, GetLastContinuation());
     lastTextFrame->mState &= ~TEXT_WHITESPACE_FLAGS;
-    lastTextFrame->mState |= NS_FRAME_IS_DIRTY;
     targetTextFrame = lastTextFrame;
   } else {
-    // Mark this frame and all the continuation frames as dirty, and fix up
-    // mContentLengths to be valid
+    // Mark all the continuation frames as dirty, and fix up mContentLengths to
+    // be valid.
+    // Don't set NS_FRAME_IS_DIRTY on |this|, since we call FrameNeedsReflow
+    // below.
     nsTextFrame* textFrame = this;
     PRInt32 newLength = nodeLength;
     do {
       textFrame->mState &= ~TEXT_WHITESPACE_FLAGS;
-      textFrame->mState |= NS_FRAME_IS_DIRTY;
       // If the text node has shrunk, clip the frame contentlength as necessary
       textFrame->mContentLength = PR_MIN(mContentLength, newLength);
       newLength -= textFrame->mContentLength;
       lastTextFrame = textFrame;
       textFrame = NS_STATIC_CAST(nsTextFrame*, textFrame->GetNextContinuation());
-    } while (textFrame);
+      if (!textFrame) {
+        break;
+      }
+      textFrame->mState |= NS_FRAME_IS_DIRTY;
+    } while (1);
     targetTextFrame = this;
   }
   // Set the length of the last text frame in the chain (necessary if the node grew)
   lastTextFrame->mContentLength = PR_MAX(0, nodeLength - lastTextFrame->mContentOffset);
 
   // Ask the parent frame to reflow me.
   aPresContext->GetPresShell()->FrameNeedsReflow(targetTextFrame,
-                                                 nsIPresShell::eStyleChange);
+                                                 nsIPresShell::eStyleChange,
+                                                 NS_FRAME_IS_DIRTY);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTextFrame::DidSetStyleContext()
 {
   ClearTextRun();
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -265,18 +265,17 @@ ViewportFrame::Reflow(nsPresContext*    
 
   nsresult rv = NS_OK;
   
   if (mFrames.NotEmpty()) {
     // Deal with a non-incremental reflow or an incremental reflow
     // targeted at our one-and-only principal child frame.
     if (aReflowState.ShouldReflowAllKids() ||
         aReflowState.mFlags.mVResize ||
-        (mFrames.FirstChild()->GetStateBits() &
-         (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
+        NS_SUBTREE_DIRTY(mFrames.FirstChild())) {
       // Reflow our one-and-only principal child frame
       nsIFrame*           kidFrame = mFrames.FirstChild();
       nsHTMLReflowMetrics kidDesiredSize;
       nsSize              availableSpace(aReflowState.availableWidth,
                                          aReflowState.availableHeight);
       nsHTMLReflowState   kidReflowState(aPresContext, aReflowState,
                                          kidFrame, availableSpace);
 
--- a/layout/mathml/base/src/nsMathMLContainerFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLContainerFrame.cpp
@@ -806,17 +806,18 @@ nsMathMLContainerFrame::RebuildAutomatic
   nsIMathMLFrame* mathMLFrame;
   aParentFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
   if (mathMLFrame) {
     mathMLFrame->TransmitAutomaticData();
   }
 }
 
 /* static */ nsresult
-nsMathMLContainerFrame::ReLayoutChildren(nsIFrame* aParentFrame)
+nsMathMLContainerFrame::ReLayoutChildren(nsIFrame* aParentFrame,
+                                         nsFrameState aBits)
 {
   if (!aParentFrame)
     return NS_OK;
 
   // walk-up to the first frame that is a MathML frame, stop if we reach <math>
   PRInt32 parentScriptLevel = 0;
   nsIFrame* frame = aParentFrame;
   while (1) {
@@ -838,17 +839,18 @@ nsMathMLContainerFrame::ReLayoutChildren
     nsIContent* content = frame->GetContent();
     NS_ASSERTION(content, "dangling frame without a content node");
     if (!content)
       break;
     // XXXldb This should check namespaces too.
     if (content->Tag() == nsGkAtoms::math)
       break;
 
-    // mark the frame dirty, and continue to climb up
+    // mark the frame dirty, and continue to climb up.  It's important that
+    // we're NOT doing this to the frame we plan to pass to FrameNeedsReflow()
     frame->AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
 
     frame = parent;
   }
 
   // re-sync the presentation data and embellishment data of our children
   RebuildAutomaticDataForChildren(frame);
 
@@ -870,17 +872,17 @@ nsMathMLContainerFrame::ReLayoutChildren
 
   // Ask our parent frame to reflow us
   nsIFrame* parent = frame->GetParent();
   NS_ASSERTION(parent, "No parent to pass the reflow request up to");
   if (!parent)
     return NS_OK;
 
   return frame->PresContext()->PresShell()->
-           FrameNeedsReflow(frame, nsIPresShell::eStyleChange);
+    FrameNeedsReflow(frame, nsIPresShell::eStyleChange, aBits);
 }
 
 // There are precise rules governing children of a MathML frame,
 // and properties such as the scriptlevel depends on those rules.
 // Hence for things to work, callers must use Append/Insert/etc wisely.
 
 nsresult
 nsMathMLContainerFrame::ChildListChanged(PRInt32 aModType)
@@ -888,23 +890,26 @@ nsMathMLContainerFrame::ChildListChanged
   // If this is an embellished frame we need to rebuild the
   // embellished hierarchy by walking-up to the parent of the
   // outermost embellished container.
   nsIFrame* frame = this;
   if (mEmbellishData.coreFrame) {
     nsIFrame* parent = mParent;
     nsEmbellishData embellishData;
     for ( ; parent; frame = parent, parent = parent->GetParent()) {
-      frame->AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
       GetEmbellishDataFrom(parent, embellishData);
       if (embellishData.coreFrame != mEmbellishData.coreFrame)
         break;
+
+      // Important: do not do this to the frame we plan to pass to
+      // ReLayoutChildren
+      frame->AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
-  return ReLayoutChildren(frame);
+  return ReLayoutChildren(frame, NS_FRAME_IS_DIRTY);
 }
 
 NS_IMETHODIMP
 nsMathMLContainerFrame::AppendFrames(nsIAtom*        aListName,
                                      nsIFrame*       aFrameList)
 {
   if (aListName) {
     return NS_ERROR_INVALID_ARG;
@@ -952,17 +957,18 @@ nsMathMLContainerFrame::AttributeChanged
   // Attributes common to MathML tags
   if (CommonAttributeChangedFor(PresContext(), mContent, aAttribute))
     return NS_OK;
 
   // XXX Since they are numerous MathML attributes that affect layout, and
   // we can't check all of them here, play safe by requesting a reflow.
   // XXXldb This should only do work for attributes that cause changes!
   return PresContext()->PresShell()->
-           FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+           FrameNeedsReflow(this, nsIPresShell::eStyleChange,
+                            NS_FRAME_IS_DIRTY);
 }
 
 nsresult 
 nsMathMLContainerFrame::ReflowChild(nsIFrame*                aChildFrame,
                                     nsPresContext*           aPresContext,
                                     nsHTMLReflowMetrics&     aDesiredSize,
                                     const nsHTMLReflowState& aReflowState,
                                     nsReflowStatus&          aStatus)
--- a/layout/mathml/base/src/nsMathMLContainerFrame.h
+++ b/layout/mathml/base/src/nsMathMLContainerFrame.h
@@ -173,20 +173,20 @@ public:
   // 1. If the MathML frame class doesn't have any cached automatic data that
   //    depends on the attribute: we just reflow (e.g., this happens with <msub>,
   //    <msup>, <mmultiscripts>, etc). This is the default behavior implemented
   //    by this base class.
   //
   // 2. If the MathML frame class has cached automatic data that depends on
   //    the attribute:
   //    2a. If the automatic data to update resides only within the descendants,
-  //        we just re-layout them using ReLayoutChildren(aPresContext, this);
+  //        we just re-layout them using ReLayoutChildren(this);
   //        (e.g., this happens with <ms>).
   //    2b. If the automatic data to update affects us in some way, we ask our parent
-  //        to re-layout its children using ReLayoutChildren(aPresContext, mParent);
+  //        to re-layout its children using ReLayoutChildren(mParent);
   //        Therefore, there is an overhead here in that our siblings are re-laid
   //        too (e.g., this happens with <mstyle>, <munder>, <mover>, <munderover>). 
   NS_IMETHOD
   AttributeChanged(PRInt32         aNameSpaceID,
                    nsIAtom*        aAttribute,
                    PRInt32         aModType);
 
   // --------------------------------------------------------------------------
@@ -296,18 +296,20 @@ public:
   // helper to blow away the automatic data cached in a frame's subtree and
   // re-layout its subtree to reflect changes that may have happen. In the
   // event where aParentFrame isn't a MathML frame, it will first walk up to
   // the ancestor that is a MathML frame, and re-layout from there -- this is
   // to guarantee that automatic data will be rebuilt properly. Note that this
   // method re-builds the automatic data in the children -- not in the parent
   // frame itself (except for those particular operations that the parent frame
   // may do do its TransmitAutomaticData()). @see RebuildAutomaticDataForChildren
+  //
+  // aBits are the bits to pass to FrameNeedsReflow() when we call it.
   static nsresult
-  ReLayoutChildren(nsIFrame* aParentFrame);
+  ReLayoutChildren(nsIFrame* aParentFrame, nsFrameState aBits);
 
 protected:
   virtual PRIntn GetSkipSides() const { return 0; }
 
   /**
    * Call DidReflow() if the NS_FRAME_IN_REFLOW frame bit is set on aFirst and
    * all its next siblings up to, but not including, aStop.
    * aStop == nsnull meaning all next siblings with the bit set.
@@ -356,38 +358,41 @@ public:
   }
 
   NS_IMETHOD
   AppendFrames(nsIAtom*        aListName,
                nsIFrame*       aFrameList)
   {
     NS_ASSERTION(!aListName, "internal error");
     nsresult rv = nsBlockFrame::AppendFrames(aListName, aFrameList);
-    nsMathMLContainerFrame::ReLayoutChildren(this);
+    nsMathMLContainerFrame::ReLayoutChildren(this,
+                                             NS_FRAME_HAS_DIRTY_CHILDREN);
     return rv;
   }
 
   NS_IMETHOD
   InsertFrames(nsIAtom*        aListName,
                nsIFrame*       aPrevFrame,
                nsIFrame*       aFrameList)
   {
     NS_ASSERTION(!aListName, "internal error");
     nsresult rv = nsBlockFrame::InsertFrames(aListName, aPrevFrame, aFrameList);
-    nsMathMLContainerFrame::ReLayoutChildren(this);
+    nsMathMLContainerFrame::ReLayoutChildren(this,
+                                             NS_FRAME_HAS_DIRTY_CHILDREN);
     return rv;
   }
 
   NS_IMETHOD
   RemoveFrame(nsIAtom*        aListName,
               nsIFrame*       aOldFrame)
   {
     NS_ASSERTION(!aListName, "internal error");
     nsresult rv = nsBlockFrame::RemoveFrame(aListName, aOldFrame);
-    nsMathMLContainerFrame::ReLayoutChildren(this);
+    nsMathMLContainerFrame::ReLayoutChildren(this,
+                                             NS_FRAME_HAS_DIRTY_CHILDREN);
     return rv;
   }
 
   virtual PRBool IsFrameOfType(PRUint32 aFlags) const {
     return nsBlockFrame::IsFrameOfType(aFlags & ~(nsIFrame::eMathML));
   }
 
 protected:
@@ -439,38 +444,41 @@ public:
   }
 
   NS_IMETHOD
   AppendFrames(nsIAtom*        aListName,
                nsIFrame*       aFrameList)
   {
     NS_ASSERTION(!aListName, "internal error");
     nsresult rv = nsInlineFrame::AppendFrames(aListName, aFrameList);
-    nsMathMLContainerFrame::ReLayoutChildren(this);
+    nsMathMLContainerFrame::ReLayoutChildren(this,
+                                             NS_FRAME_HAS_DIRTY_CHILDREN);
     return rv;
   }
 
   NS_IMETHOD
   InsertFrames(nsIAtom*        aListName,
                nsIFrame*       aPrevFrame,
                nsIFrame*       aFrameList)
   {
     NS_ASSERTION(!aListName, "internal error");
     nsresult rv = nsInlineFrame::InsertFrames(aListName, aPrevFrame, aFrameList);
-    nsMathMLContainerFrame::ReLayoutChildren(this);
+    nsMathMLContainerFrame::ReLayoutChildren(this,
+                                             NS_FRAME_HAS_DIRTY_CHILDREN);
     return rv;
   }
 
   NS_IMETHOD
   RemoveFrame(nsIAtom*        aListName,
               nsIFrame*       aOldFrame)
   {
     NS_ASSERTION(!aListName, "internal error");
     nsresult rv = nsInlineFrame::RemoveFrame(aListName, aOldFrame);
-    nsMathMLContainerFrame::ReLayoutChildren(this);
+    nsMathMLContainerFrame::ReLayoutChildren(this,
+                                             NS_FRAME_HAS_DIRTY_CHILDREN);
     return rv;
   }
 
   virtual PRBool IsFrameOfType(PRUint32 aFlags) const {
     // Override nsInlineFrame.   XXX Should we really?
     if (aFlags & (nsIFrame::eBidiInlineContainer))
       return PR_FALSE;
     return nsInlineFrame::IsFrameOfType(aFlags & ~(nsIFrame::eMathML));
--- a/layout/mathml/base/src/nsMathMLmactionFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLmactionFrame.cpp
@@ -1,8 +1,9 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -384,32 +385,32 @@ nsMathMLmactionFrame::MouseClick(nsIDOME
       nsAutoString value;
       char cbuf[10];
       PR_snprintf(cbuf, sizeof(cbuf), "%d", selection);
       value.AssignASCII(cbuf);
       PRBool notify = PR_FALSE; // don't yet notify the document
       mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::selection_, value, notify);
 
       // Now trigger a content-changed reflow...
-      mSelectedFrame->AddStateBits(NS_FRAME_IS_DIRTY);
       PresContext()->PresShell()->
-        FrameNeedsReflow(mSelectedFrame, nsIPresShell::eTreeChange);
+        FrameNeedsReflow(mSelectedFrame, nsIPresShell::eTreeChange,
+                         NS_FRAME_IS_DIRTY);
     }
   }
   else if (NS_MATHML_ACTION_TYPE_RESTYLE == mActionType) {
     if (!mRestyle.IsEmpty()) {
       nsCOMPtr<nsIDOMElement> node( do_QueryInterface(mContent) );
       if (node.get()) {
         if (nsContentUtils::HasNonEmptyAttr(mContent, kNameSpaceID_None,
                                             nsGkAtoms::actiontype_))
           node->RemoveAttribute(NS_LITERAL_STRING("actiontype"));
         else
           node->SetAttribute(NS_LITERAL_STRING("actiontype"), mRestyle);
 
         // Trigger a style change reflow
-        mSelectedFrame->AddStateBits(NS_FRAME_IS_DIRTY);
         PresContext()->PresShell()->
-          FrameNeedsReflow(mSelectedFrame, nsIPresShell::eStyleChange);
+          FrameNeedsReflow(mSelectedFrame, nsIPresShell::eStyleChange,
+                           NS_FRAME_IS_DIRTY);
       }
     }
   }
   return NS_OK;
 }
--- a/layout/mathml/base/src/nsMathMLmoFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLmoFrame.cpp
@@ -995,17 +995,17 @@ nsMathMLmoFrame::AttributeChanged(PRInt3
     nsIFrame* target = this;
     nsEmbellishData embellishData;
     do {
       target = target->GetParent();
       GetEmbellishDataFrom(target, embellishData);
     } while (embellishData.coreFrame == this);
 
     // we have automatic data to update in the children of the target frame
-    return ReLayoutChildren(target);
+    return ReLayoutChildren(target, NS_FRAME_IS_DIRTY);
   }
 
   return nsMathMLTokenFrame::
          AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 // ----------------------
 // No need to tract the style context given to our MathML char. 
--- a/layout/mathml/base/src/nsMathMLmoverFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLmoverFrame.cpp
@@ -69,17 +69,17 @@ nsMathMLmoverFrame::~nsMathMLmoverFrame(
 NS_IMETHODIMP
 nsMathMLmoverFrame::AttributeChanged(PRInt32         aNameSpaceID,
                                      nsIAtom*        aAttribute,
                                      PRInt32         aModType)
 {
   if (nsGkAtoms::accent_ == aAttribute) {
     // When we have automatic data to update within ourselves, we ask our
     // parent to re-layout its children
-    return ReLayoutChildren(mParent);
+    return ReLayoutChildren(mParent, NS_FRAME_IS_DIRTY);
   }
 
   return nsMathMLContainerFrame::
          AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 NS_IMETHODIMP
 nsMathMLmoverFrame::UpdatePresentationData(PRInt32         aScriptLevelIncrement,
--- a/layout/mathml/base/src/nsMathMLmstyleFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLmstyleFrame.cpp
@@ -163,10 +163,10 @@ nsMathMLmstyleFrame::AttributeChanged(PR
   if (CommonAttributeChangedFor(PresContext(), mContent, aAttribute))
     return NS_OK;
 
   // Other attributes can affect too many things, ask our parent to re-layout
   // its children so that we can pick up changes in our attributes & transmit
   // them in our subtree. However, our siblings will be re-laid too. We used
   // to have a more speedier but more verbose alternative that didn't re-layout
   // our siblings. See bug 114909 - attachment 67668.
-  return ReLayoutChildren(mParent);
+  return ReLayoutChildren(mParent, NS_FRAME_IS_DIRTY);
 }
--- a/layout/mathml/base/src/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLmtableFrame.cpp
@@ -443,28 +443,30 @@ nsMathMLmtableOuterFrame::AttributeChang
     return NS_OK;
   nsIFrame* rgFrame = tableFrame->GetFirstChild(nsnull);
   if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
     return NS_OK;
 
   // align - just need to issue a dirty (resize) reflow command
   if (aAttribute == nsGkAtoms::align) {
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eResize);
+      FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
     return NS_OK;
   }
 
   // displaystyle - may seem innocuous, but it is actually very harsh --
   // like changing an unit. Blow away and recompute all our automatic
   // presentational data, and issue a style-changed reflow request
   if (aAttribute == nsGkAtoms::displaystyle_) {
     nsMathMLContainerFrame::RebuildAutomaticDataForChildren(mParent);
     nsMathMLContainerFrame::PropagateScriptStyleFor(tableFrame, mPresentationData.scriptLevel);
+    // XXXbz I have no idea why this is reflowing the _parent_ instead of
+    // us...
     PresContext()->PresShell()->
-      FrameNeedsReflow(mParent, nsIPresShell::eStyleChange);
+      FrameNeedsReflow(mParent, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     return NS_OK;
   }
 
   // ...and the other attributes affect rows or columns in one way or another
   nsIAtom* MOZrowAtom = nsnull;
   nsIAtom* MOZcolAtom = nsnull;
   if (aAttribute == nsGkAtoms::rowalign_)
     MOZrowAtom = nsGkAtoms::MOZrowalign;
--- a/layout/mathml/base/src/nsMathMLmunderFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLmunderFrame.cpp
@@ -69,17 +69,17 @@ nsMathMLmunderFrame::~nsMathMLmunderFram
 NS_IMETHODIMP
 nsMathMLmunderFrame::AttributeChanged(PRInt32         aNameSpaceID,
                                       nsIAtom*        aAttribute,
                                       PRInt32         aModType)
 {
   if (nsGkAtoms::accentunder_ == aAttribute) {
     // When we have automatic data to update within ourselves, we ask our
     // parent to re-layout its children
-    return ReLayoutChildren(mParent);
+    return ReLayoutChildren(mParent, NS_FRAME_IS_DIRTY);
   }
 
   return nsMathMLContainerFrame::
          AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 NS_IMETHODIMP
 nsMathMLmunderFrame::UpdatePresentationData(PRInt32         aScriptLevelIncrement,
--- a/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp
@@ -70,17 +70,17 @@ NS_IMETHODIMP
 nsMathMLmunderoverFrame::AttributeChanged(PRInt32         aNameSpaceID,
                                           nsIAtom*        aAttribute,
                                           PRInt32         aModType)
 {
   if (nsGkAtoms::accent_ == aAttribute ||
       nsGkAtoms::accentunder_ == aAttribute) {
     // When we have automatic data to update within ourselves, we ask our
     // parent to re-layout its children
-    return ReLayoutChildren(mParent);
+    return ReLayoutChildren(mParent, NS_FRAME_IS_DIRTY);
   }
 
   return nsMathMLContainerFrame::
          AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 NS_IMETHODIMP
 nsMathMLmunderoverFrame::UpdatePresentationData(PRInt32         aScriptLevelIncrement,
--- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
@@ -489,18 +489,17 @@ void nsSVGForeignObjectFrame::RequestRef
   if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
     // If we haven't had an InitialUpdate yet, nothing to do.
     return;
 
   nsIFrame* kid = GetFirstChild(nsnull);
   if (!kid)
     return;
 
-  kid->AddStateBits(NS_FRAME_IS_DIRTY);
-  PresContext()->PresShell()->FrameNeedsReflow(kid, aType);
+  PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY);
 }
 
 void nsSVGForeignObjectFrame::UpdateGraphic()
 {
   if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
     return;
 
   nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
@@ -375,19 +375,18 @@ nsDisplaySVG::Paint(nsDisplayListBuilder
 NS_IMETHODIMP
 nsSVGOuterSVGFrame::AttributeChanged(PRInt32         aNameSpaceID,
                                      nsIAtom*        aAttribute,
                                      PRInt32         aModType)
 {
   if (aNameSpaceID == kNameSpaceID_None &&
       !(GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
       (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
-    AddStateBits(NS_FRAME_IS_DIRTY);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+      FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
   }
 
   return NS_OK;
 }
 
 nsIFrame*
 nsSVGOuterSVGFrame::GetFrameForPoint(const nsPoint& aPoint)
 {
@@ -632,17 +631,18 @@ nsSVGOuterSVGFrame::GetCanvasTM()
 //----------------------------------------------------------------------
 // Implementation helpers
 
 void nsSVGOuterSVGFrame::InitiateReflow()
 {
   mNeedsReflow = PR_FALSE;
   
   nsIPresShell* presShell = PresContext()->PresShell();
-  presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+  presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
+                              NS_FRAME_IS_DIRTY);
   // XXXbz why is this synchronously flushing reflows, exactly?  If it
   // needs to, why is it not using the presshell's reflow batching
   // instead of hacking its own?
   presShell->FlushPendingNotifications(Flush_OnlyReflow);  
 }
 
 
 void
--- a/layout/tables/nsTableColGroupFrame.cpp
+++ b/layout/tables/nsTableColGroupFrame.cpp
@@ -264,19 +264,19 @@ nsTableColGroupFrame::InsertColsReflow(P
                                        nsIFrame*       aLastFrame)
 {
   AddColsToTable(aColIndex, PR_TRUE, aFirstFrame, aLastFrame);
 
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   if (!tableFrame)
     return;
 
-  tableFrame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   PresContext()->PresShell()->FrameNeedsReflow(tableFrame,
-                                                  nsIPresShell::eTreeChange);
+                                               nsIPresShell::eTreeChange,
+                                               NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
 void
 nsTableColGroupFrame::RemoveChild(nsTableColFrame& aChild,
                                   PRBool           aResetSubsequentColIndices)
 {
   PRInt32 colIndex = 0;
   nsIFrame* nextChild = nsnull;
@@ -296,19 +296,19 @@ nsTableColGroupFrame::RemoveChild(nsTabl
           ResetColIndices(nextGroup, colIndex);
       }
     }
   }
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   if (!tableFrame)
     return;
 
-  tableFrame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   PresContext()->PresShell()->FrameNeedsReflow(tableFrame,
-                                                  nsIPresShell::eTreeChange);
+                                               nsIPresShell::eTreeChange,
+                                               NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
 NS_IMETHODIMP
 nsTableColGroupFrame::RemoveFrame(nsIAtom*        aListName,
                                   nsIFrame*       aOldFrame)
 {
   NS_ASSERTION(!aListName, "unexpected child list");
 
@@ -320,19 +320,19 @@ nsTableColGroupFrame::RemoveFrame(nsIAto
     RemoveChild(*colFrame, PR_TRUE);
     
     nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     if (!tableFrame)
       return NS_ERROR_NULL_POINTER;
 
     tableFrame->RemoveCol(this, colIndex, PR_TRUE, PR_TRUE);
 
-    tableFrame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     PresContext()->PresShell()->FrameNeedsReflow(tableFrame,
-                                                    nsIPresShell::eTreeChange);
+                                                 nsIPresShell::eTreeChange,
+                                                 NS_FRAME_HAS_DIRTY_CHILDREN);
   }
   else {
     mFrames.DestroyFrame(aOldFrame);
   }
 
   return NS_OK;
 }
 
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -407,21 +407,20 @@ void nsTableFrame::AttributeChangedFor(n
         PRInt32 rowIndex, colIndex;
         cellFrame->GetRowIndex(rowIndex);
         cellFrame->GetColIndex(colIndex);
         RemoveCell(cellFrame, rowIndex);
         nsAutoVoidArray cells;
         cells.AppendElement(cellFrame);
         InsertCells(cells, rowIndex, colIndex - 1);
 
-        AddStateBits(NS_FRAME_IS_DIRTY);
         // XXX Should this use eStyleChange?  It currently doesn't need
         // to, but it might given more optimization.
-        PresContext()->PresShell()->FrameNeedsReflow(this,
-          nsIPresShell::eTreeChange);
+        PresContext()->PresShell()->
+          FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
       }
     }
   }
 }
 
 
 /* ****** CellMap methods ******* */
 
@@ -1866,17 +1865,17 @@ NS_METHOD nsTableFrame::Reflow(nsPresCon
   PRBool reflowedChildren  = PR_FALSE;
 
   // Reflow the entire table (pass 2 and possibly pass 3). This phase is necessary during a 
   // constrained initial reflow and other reflows which require either a strategy init or balance. 
   // This isn't done during an unconstrained reflow, because it will occur later when the parent 
   // reflows with a constrained width.
   PRBool needToInitiateSpecialReflow =
     !!(GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
-  if ((GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) ||
+  if (NS_SUBTREE_DIRTY(this) ||
       aReflowState.ShouldReflowAllKids() ||
       IsGeometryDirty() ||
       needToInitiateSpecialReflow) {
     // see if an extra reflow will be necessary in pagination mode when there is a specified table height 
     if (isPaginated && !GetPrevInFlow() && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) {
       nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
       if ((tableSpecifiedHeight > 0) && 
           (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) {
@@ -2253,19 +2252,18 @@ nsTableFrame::AppendFrames(nsIAtom*     
     // Move to the next frame
     f = next;
   }
 
 #ifdef DEBUG_TABLE_CELLMAP
   printf("=== TableFrame::AppendFrames\n");
   Dump(PR_TRUE, PR_TRUE, PR_TRUE);
 #endif
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-  PresContext()->PresShell()->FrameNeedsReflow(this,
-                                                  nsIPresShell::eTreeChange);
+  PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                                               NS_FRAME_HAS_DIRTY_CHILDREN);
   SetGeometryDirty();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTableFrame::InsertFrames(nsIAtom*        aListName,
                            nsIFrame*       aPrevFrame,
@@ -2361,19 +2359,18 @@ nsTableFrame::InsertFrames(nsIAtom*     
     InsertRowGroups(aFrameList, lastSibling);
   } else {
     NS_ASSERTION(!aListName, "unexpected child list");
     // Just insert the frame and don't worry about reflowing it
     mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList);
     return NS_OK;
   }
 
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-  PresContext()->PresShell()->FrameNeedsReflow(this,
-                                                  nsIPresShell::eTreeChange);
+  PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                                               NS_FRAME_HAS_DIRTY_CHILDREN);
   SetGeometryDirty();
 #ifdef DEBUG_TABLE_CELLMAP
   printf("=== TableFrame::InsertFrames\n");
   Dump(PR_TRUE, PR_TRUE, PR_TRUE);
 #endif
   return NS_OK;
 }
 
@@ -2441,19 +2438,18 @@ nsTableFrame::RemoveFrame(nsIAtom*      
     }
   }
   // for now, just bail and recalc all of the collapsing borders
   // XXXldb [reflow branch merging 20060830] do we still need this?
   if (IsBorderCollapse()) {
     nsRect damageArea(0, 0, PR_MAX(1, GetColCount()), PR_MAX(1, GetRowCount()));
     SetBCDamageArea(damageArea);
   }
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-  PresContext()->PresShell()->FrameNeedsReflow(this,
-                                                  nsIPresShell::eTreeChange);
+  PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                                               NS_FRAME_HAS_DIRTY_CHILDREN);
   SetGeometryDirty();
 #ifdef DEBUG_TABLE_CELLMAP
   printf("=== TableFrame::RemoveFrame\n");
   Dump(PR_TRUE, PR_TRUE, PR_TRUE);
 #endif
   return NS_OK;
 }
 
@@ -2732,18 +2728,17 @@ nsTableFrame::ReflowChildren(nsTableRefl
   nsTableRowGroupFrame *thead, *tfoot;
   OrderRowGroups(rowGroups, numRowGroups, &thead, &tfoot);
   PRBool pageBreak = PR_FALSE;
   for (PRUint32 childX = 0; childX < numRowGroups; childX++) {
     nsIFrame* kidFrame = (nsIFrame*)rowGroups.ElementAt(childX);
     // Get the frame state bits
     // See if we should only reflow the dirty child frames
     if (reflowAllKids ||
-        (kidFrame->GetStateBits() & (NS_FRAME_IS_DIRTY |
-                                     NS_FRAME_HAS_DIRTY_CHILDREN)) ||
+        NS_SUBTREE_DIRTY(kidFrame) ||
         (aReflowState.reflowState.mFlags.mSpecialHeightReflow &&
          (isPaginated || (kidFrame->GetStateBits() &
                           NS_FRAME_CONTAINS_RELATIVE_HEIGHT)))) {
       if (pageBreak) {
         PushChildren(rowGroups, childX);
         aStatus = NS_FRAME_NOT_COMPLETE;
         break;
       }
--- a/layout/tables/nsTableOuterFrame.cpp
+++ b/layout/tables/nsTableOuterFrame.cpp
@@ -279,20 +279,19 @@ nsTableOuterFrame::AppendFrames(nsIAtom*
                  aFrameList->GetType() == nsGkAtoms::tableCaptionFrame,
                  "appending non-caption frame to captionList");
     mCaptionFrames.AppendFrames(this, aFrameList);
     mCaptionFrame = mCaptionFrames.FirstChild();
     rv = NS_OK;
 
     // Reflow the new caption frame. It's already marked dirty, so
     // just tell the pres shell.
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange);
-    
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN);
   }
   else {
     NS_PRECONDITION(PR_FALSE, "unexpected child list");
     rv = NS_ERROR_UNEXPECTED;
   }
 
   return rv;
 }
@@ -333,19 +332,19 @@ nsTableOuterFrame::RemoveFrame(nsIAtom* 
     // we're going to need to reflow it. Mark it dirty
     mInnerTableFrame->AddStateBits(NS_FRAME_IS_DIRTY);
   }
 
   // Remove the frame and destroy it
   mCaptionFrames.DestroyFrame(aOldFrame);
   mCaptionFrame = mCaptionFrames.FirstChild();
   
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); // also means child removed
   PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                     NS_FRAME_HAS_DIRTY_CHILDREN); // also means child removed
 
   return NS_OK;
 }
 
 NS_METHOD 
 nsTableOuterFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                     const nsRect&           aDirtyRect,
                                     const nsDisplayListSet& aLists)
@@ -1182,20 +1181,19 @@ NS_METHOD nsTableOuterFrame::Reflow(nsPr
     reflowAllKids = PR_TRUE;
 
   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     // Set up our kids.  They're already present, on an overflow list, 
     // or there are none so we'll create them now
     MoveOverflowToChildList(aPresContext);
   }
 
-  PRBool reflowCaption = mCaptionFrame && (reflowAllKids || (mCaptionFrame->
-    GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)));
-  PRBool reflowInner = reflowAllKids || (mInnerTableFrame->
-    GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN));
+  PRBool reflowCaption =
+    mCaptionFrame && (reflowAllKids || NS_SUBTREE_DIRTY(mCaptionFrame));
+  PRBool reflowInner = reflowAllKids || NS_SUBTREE_DIRTY(mInnerTableFrame);
 
   // First reflow the caption.  nsHTMLReflowState takes care of making
   // side captions small.
   nsHTMLReflowMetrics captionMet;
   nsSize captionSize;
   nsMargin captionMargin;
   // Use longs to get more-aligned space.
   #define LONGS_IN_HTMLRS \
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -191,19 +191,18 @@ nsTableRowFrame::AppendFrames(nsIAtom*  
   for (nsIFrame* childFrame = aFrameList; childFrame;
        childFrame = childFrame->GetNextSibling()) {
     if (IS_TABLE_CELL(childFrame->GetType())) {
       // Add the cell to the cell map
       tableFrame->AppendCell((nsTableCellFrame&)*childFrame, GetRowIndex());
     }
   }
 
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-  PresContext()->PresShell()->FrameNeedsReflow(this,
-                                                  nsIPresShell::eTreeChange);
+  PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                                               NS_FRAME_HAS_DIRTY_CHILDREN);
   tableFrame->SetGeometryDirty();
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsTableRowFrame::InsertFrames(nsIAtom*        aListName,
@@ -232,19 +231,18 @@ nsTableRowFrame::InsertFrames(nsIAtom*  
   if (prevCellFrame) {
     prevCellFrame->GetColIndex(colIndex);
   }
   tableFrame->InsertCells(cellChildren, GetRowIndex(), colIndex);
 
   // Insert the frames in the frame list
   mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
   
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-  PresContext()->PresShell()->FrameNeedsReflow(this,
-                                                  nsIPresShell::eTreeChange);
+  PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                                               NS_FRAME_HAS_DIRTY_CHILDREN);
   tableFrame->SetGeometryDirty();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTableRowFrame::RemoveFrame(nsIAtom*        aListName,
                              nsIFrame*       aOldFrame)
@@ -258,19 +256,19 @@ nsTableRowFrame::RemoveFrame(nsIAtom*   
       PRInt32 colIndex;
       cellFrame->GetColIndex(colIndex);
       // remove the cell from the cell map
       tableFrame->RemoveCell(cellFrame, GetRowIndex());
 
       // Remove the frame and destroy it
       mFrames.DestroyFrame(aOldFrame);
 
-      AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-      PresContext()->PresShell()->FrameNeedsReflow(this,
-                                                    nsIPresShell::eTreeChange);
+      PresContext()->PresShell()->
+        FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                         NS_FRAME_HAS_DIRTY_CHILDREN);
       tableFrame->SetGeometryDirty();
     }
     else {
       NS_ERROR("unexpected frame type");
       return NS_ERROR_INVALID_ARG;
     }
   }
 
@@ -818,18 +816,17 @@ nsTableRowFrame::ReflowChildren(nsPresCo
     }
 
     nsTableCellFrame* cellFrame = NS_STATIC_CAST(nsTableCellFrame*, kidFrame);
 
     // See if we should only reflow the dirty child frames
     PRBool doReflowChild = PR_TRUE;
     if (!aReflowState.ShouldReflowAllKids() &&
         !aTableFrame.IsGeometryDirty() &&
-        !(kidFrame->GetStateBits() &
-          (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
+        !NS_SUBTREE_DIRTY(kidFrame)) {
       if (!aReflowState.mFlags.mSpecialHeightReflow)
         doReflowChild = PR_FALSE;
     }
     else if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) {
       // We don't reflow a rowspan >1 cell here with a constrained height. 
       // That happens in nsTableRowGroupFrame::SplitSpanningCells.
       if (aTableFrame.GetEffectiveRowSpan(*cellFrame) > 1) {
         doReflowChild = PR_FALSE;
@@ -870,18 +867,17 @@ nsTableRowFrame::ReflowChildren(nsPresCo
       // it is a style change reflow or we are printing, then we must reflow the
       // cell. Otherwise we can skip the reflow.
       // XXXldb Why is this condition distinct from doReflowChild above?
       nsSize cellDesiredSize = cellFrame->GetDesiredSize();
       if ((availCellWidth != cellFrame->GetPriorAvailWidth())       ||
           (cellDesiredSize.width > cellFrame->GetPriorAvailWidth()) ||
           (GetStateBits() & NS_FRAME_IS_DIRTY)                      ||
           isPaginated                                               ||
-          (cellFrame->GetStateBits() &
-           (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))       ||
+          NS_SUBTREE_DIRTY(cellFrame)                               ||
           // See if it needs a special reflow, or if it had one that we need to undo.
           (cellFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT) ||
           HasPctHeight()) {
         // Reflow the cell to fit the available width, height
         // XXX The old IR_ChildIsDirty code used availCellWidth here.
         nsSize  kidAvailSize(availColWidth, aReflowState.availableHeight);
 
         // Reflow the child
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -379,18 +379,17 @@ nsTableRowGroupFrame::ReflowChildren(nsP
       NS_NOTREACHED("yikes, a non-row child");
       continue;
     }
 
     haveRow = PR_TRUE;
 
     // Reflow the row frame
     if (reflowAllKids ||
-        (kidFrame->GetStateBits() &
-         (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) ||
+        NS_SUBTREE_DIRTY(kidFrame) ||
         (aReflowState.reflowState.mFlags.mSpecialHeightReflow &&
          (isPaginated || (kidFrame->GetStateBits() &
                           NS_FRAME_CONTAINS_RELATIVE_HEIGHT)))) {
       nsSize oldKidSize = kidFrame->GetSize();
 
       // XXXldb We used to only pass aDesiredSize.mFlags through for the
       // incremental reflow codepath.
       nsHTMLReflowMetrics desiredSize(aDesiredSize.mFlags);
@@ -1337,19 +1336,19 @@ nsTableRowGroupFrame::AppendFrames(nsIAt
   PRInt32 rowIndex = GetRowCount();
   // Append the frames to the sibling chain
   mFrames.AppendFrames(nsnull, aFrameList);
 
   if (rows.Count() > 0) {
     nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     if (tableFrame) {
       tableFrame->AppendRows(*this, rowIndex, rows);
-      AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-      PresContext()->PresShell()->FrameNeedsReflow(this,
-                                                    nsIPresShell::eTreeChange);
+      PresContext()->PresShell()->
+        FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                         NS_FRAME_HAS_DIRTY_CHILDREN);
       tableFrame->SetGeometryDirty();
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1387,19 +1386,19 @@ nsTableRowGroupFrame::InsertFrames(nsIAt
   mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
 
   PRInt32 numRows = rows.Count();
   if (numRows > 0) {
     nsTableRowFrame* prevRow = (nsTableRowFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsGkAtoms::tableRowFrame);
     PRInt32 rowIndex = (prevRow) ? prevRow->GetRowIndex() + 1 : startRowIndex;
     tableFrame->InsertRows(*this, rows, rowIndex, PR_TRUE);
 
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-    PresContext()->PresShell()->FrameNeedsReflow(this,
-                                                    nsIPresShell::eTreeChange);
+    PresContext()->PresShell()->
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN);
     tableFrame->SetGeometryDirty();
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTableRowGroupFrame::RemoveFrame(nsIAtom*        aListName,
                                   nsIFrame*       aOldFrame)
@@ -1409,19 +1408,19 @@ nsTableRowGroupFrame::RemoveFrame(nsIAto
   ClearRowCursor();
 
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   if (tableFrame) {
     if (nsGkAtoms::tableRowFrame == aOldFrame->GetType()) {
       // remove the rows from the table (and flag a rebalance)
       tableFrame->RemoveRows((nsTableRowFrame &)*aOldFrame, 1, PR_TRUE);
 
-      AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-      PresContext()->PresShell()->FrameNeedsReflow(this,
-                                                    nsIPresShell::eTreeChange);
+      PresContext()->PresShell()->
+        FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                         NS_FRAME_HAS_DIRTY_CHILDREN);
       tableFrame->SetGeometryDirty();
     }
   }
   mFrames.DestroyFrame(aOldFrame);
 
   return NS_OK;
 }
 
--- a/layout/xul/base/src/grid/nsGridRow.cpp
+++ b/layout/xul/base/src/grid/nsGridRow.cpp
@@ -87,18 +87,18 @@ nsGridRow::MarkDirty(nsBoxLayoutState& a
   mPref = -1;
   mMin = -1;
   mMax = -1;
   mFlex = -1;
   mTop = -1;
   mBottom = -1;
 
   if (mBox) {
-    mBox->AddStateBits(NS_FRAME_IS_DIRTY);
-    aState.PresShell()->FrameNeedsReflow(mBox, nsIPresShell::eTreeChange);
+    aState.PresShell()->FrameNeedsReflow(mBox, nsIPresShell::eTreeChange,
+                                         NS_FRAME_IS_DIRTY);
   }
 }
 
 PRBool 
 nsGridRow::IsCollapsed(nsBoxLayoutState& aState)
 {
   return mBox && mBox->IsCollapsed(aState);
 }
--- a/layout/xul/base/src/grid/nsGridRowGroupLayout.cpp
+++ b/layout/xul/base/src/grid/nsGridRowGroupLayout.cpp
@@ -182,20 +182,20 @@ nsGridRowGroupLayout::GetMinSize(nsIBox*
 /*
  * Run down through our children dirtying them recursively.
  */
 void
 nsGridRowGroupLayout::DirtyRows(nsIBox* aBox, nsBoxLayoutState& aState)
 {
   if (aBox) {
     // mark us dirty
-    aBox->AddStateBits(NS_FRAME_IS_DIRTY);
     // XXXldb We probably don't want to walk up the ancestor chain
     // calling MarkIntrinsicWidthsDirty for every row group.
-    aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange);
+    aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange,
+                                         NS_FRAME_IS_DIRTY);
     nsIBox* child = aBox->GetChildBox();
 
     while(child) {
 
       // walk into scrollframes
       nsIBox* deepChild = nsGrid::GetScrolledBox(child);
 
       // walk into other monuments
--- a/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp
+++ b/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp
@@ -310,20 +310,20 @@ nsGridRowLeafLayout::Layout(nsIBox* aBox
   return nsGridRowLayout::Layout(aBox, aBoxLayoutState);
 }
 
 void
 nsGridRowLeafLayout::DirtyRows(nsIBox* aBox, nsBoxLayoutState& aState)
 {
   if (aBox) {
     // mark us dirty
-    aBox->AddStateBits(NS_FRAME_IS_DIRTY);
     // XXXldb We probably don't want to walk up the ancestor chain
     // calling MarkIntrinsicWidthsDirty for every row.
-    aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange);
+    aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange,
+                                         NS_FRAME_IS_DIRTY);
   }
 }
 
 void
 nsGridRowLeafLayout::CountRowsColumns(nsIBox* aBox, PRInt32& aRowCount, PRInt32& aComputedColumnCount)
 {
   if (aBox) {
     nsIBox* child = aBox->GetChildBox();
--- a/layout/xul/base/src/nsBoxFrame.cpp
+++ b/layout/xul/base/src/nsBoxFrame.cpp
@@ -1032,19 +1032,19 @@ nsBoxFrame::RemoveFrame(nsIAtom*        
   // notify the layout manager
   if (mLayoutManager)
     mLayoutManager->ChildrenRemoved(this, state, aOldFrame);
 
   // destroy the child frame
   aOldFrame->Destroy();
 
   // mark us dirty and generate a reflow command
-  mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
   PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                     NS_FRAME_HAS_DIRTY_CHILDREN);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBoxFrame::InsertFrames(nsIAtom*        aListName,
                          nsIFrame*       aPrevFrame,
                          nsIFrame*       aFrameList)
 {
@@ -1061,19 +1061,19 @@ nsBoxFrame::InsertFrames(nsIAtom*       
      mLayoutManager->ChildrenInserted(this, state, aPrevFrame, aFrameList);
 
 #ifdef DEBUG_LAYOUT
    // if we are in debug make sure our children are in debug as well.
    if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
        SetDebugOnChildList(state, mFrames.FirstChild(), PR_TRUE);
 #endif
 
-   mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
    PresContext()->PresShell()->
-     FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+     FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                      NS_FRAME_HAS_DIRTY_CHILDREN);
    return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsBoxFrame::AppendFrames(nsIAtom*        aListName,
                          nsIFrame*       aFrameList)
 {
@@ -1088,20 +1088,21 @@ nsBoxFrame::AppendFrames(nsIAtom*       
      mLayoutManager->ChildrenAppended(this, state, aFrameList);
 
 #ifdef DEBUG_LAYOUT
    // if we are in debug make sure our children are in debug as well.
    if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
        SetDebugOnChildList(state, mFrames.FirstChild(), PR_TRUE);
 #endif
 
+   // XXXbz why is this NS_FRAME_FIRST_REFLOW check here?
    if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
-     mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
      PresContext()->PresShell()->
-       FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                        NS_FRAME_HAS_DIRTY_CHILDREN);
    }
    return NS_OK;
 }
 
 
 
 NS_IMETHODIMP
 nsBoxFrame::AttributeChanged(PRInt32 aNameSpaceID,
@@ -1204,39 +1205,38 @@ nsBoxFrame::AttributeChanged(PRInt32 aNa
     else if (aAttribute == nsGkAtoms::left ||
              aAttribute == nsGkAtoms::top) {
       mState &= ~NS_STATE_STACK_NOT_POSITIONED;
     }
     else if (aAttribute == nsGkAtoms::mousethrough) {
       UpdateMouseThrough();
     }
 
-    mState |= NS_FRAME_IS_DIRTY;
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+      FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
   }
   else if (aAttribute == nsGkAtoms::ordinal) {
     nsBoxLayoutState state(PresContext());
 
     nsIFrame* frameToMove = this;
     if (GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
       PresContext()->PresShell()->GetPlaceholderFrameFor(this,
                                                             &frameToMove);
       NS_ASSERTION(frameToMove, "Out of flow without placeholder?");
     }
     
     nsIBox* parent = frameToMove->GetParentBox();
     // If our parent is not a box, there's not much we can do... but in that
     // case our ordinal doesn't matter anyway, so that's ok.
     if (parent) {
       parent->RelayoutChildAtOrdinal(state, frameToMove);
-      mState |= NS_FRAME_IS_DIRTY;
       // XXXldb Should this instead be a tree change on the child or parent?
       PresContext()->PresShell()->
-        FrameNeedsReflow(frameToMove, nsIPresShell::eStyleChange);
+        FrameNeedsReflow(parent, nsIPresShell::eStyleChange,
+                         NS_FRAME_IS_DIRTY);
     }
   }
   // If the accesskey changed, register for the new value
   // The old value has been unregistered in nsXULElement::SetAttr
   else if (aAttribute == nsGkAtoms::accesskey) {
     RegUnregAccessKey(PR_TRUE);
   }
 
@@ -1403,17 +1403,17 @@ nsBoxFrame::PaintXULDebugBackground(nsIR
   r = inner;
   r.y = r.y + r.height - debugBorder.bottom;
   r.height = debugBorder.bottom;
   aRenderingContext.FillRect(r);
 
   
   // if we have dirty children or we are dirty 
   // place a green border around us.
-  if (GetStateBits & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) {
+  if (NS_SUBTREE_DIRTY(this)) {
      nsRect dirtyr(inner);
      aRenderingContext.SetColor(NS_RGB(0,255,0));
      aRenderingContext.DrawRect(dirtyr);
      aRenderingContext.SetColor(color);
   }
 }
 
 void
@@ -2048,17 +2048,17 @@ nsBoxFrame::GetLayoutManager(nsIBoxLayou
 
 nsresult
 nsBoxFrame::LayoutChildAt(nsBoxLayoutState& aState, nsIBox* aBox, const nsRect& aRect)
 {
   // get the current rect
   nsRect oldRect(aBox->GetRect());
   aBox->SetBounds(aState, aRect);
 
-  PRBool layout = (aBox->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0;
+  PRBool layout = NS_SUBTREE_DIRTY(aBox);
   
   if (layout || (oldRect.width != aRect.width || oldRect.height != aRect.height))  {
     return aBox->Layout(aState);
   }
 
   return NS_OK;
 }
 
--- a/layout/xul/base/src/nsImageBoxFrame.cpp
+++ b/layout/xul/base/src/nsImageBoxFrame.cpp
@@ -167,19 +167,18 @@ nsImageBoxFrame::AttributeChanged(PRInt3
                                   nsIAtom* aAttribute,
                                   PRInt32 aModType)
 {
   nsresult rv = nsLeafBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
                                                  aModType);
 
   if (aAttribute == nsGkAtoms::src) {
     UpdateImage();
-    AddStateBits(NS_FRAME_IS_DIRTY);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+      FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
   }
   else if (aAttribute == nsGkAtoms::validate)
     UpdateLoadFlags();
 
   return rv;
 }
 
 nsImageBoxFrame::nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext):
@@ -503,19 +502,18 @@ NS_IMETHODIMP nsImageBoxFrame::OnStartCo
   nscoord w, h;
   image->GetWidth(&w);
   image->GetHeight(&h);
 
   mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(w),
                         nsPresContext::CSSPixelsToAppUnits(h));
 
   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
-    AddStateBits(NS_FRAME_IS_DIRTY);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+      FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsImageBoxFrame::OnStopContainer(imgIRequest *request,
                                                imgIContainer *image)
 {
@@ -530,19 +528,18 @@ NS_IMETHODIMP nsImageBoxFrame::OnStopDec
                                             const PRUnichar *statusArg)
 {
   if (NS_SUCCEEDED(aStatus))
     // Fire an onload DOM event.
     FireImageDOMEvent(mContent, NS_LOAD);
   else {
     // Fire an onerror DOM event.
     mIntrinsicSize.SizeTo(0, 0);
-    AddStateBits(NS_FRAME_IS_DIRTY);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+      FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     FireImageDOMEvent(mContent, NS_LOAD_ERROR);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIContainer *container,
                                             gfxIImageFrame *newframe,
--- a/layout/xul/base/src/nsListBoxBodyFrame.cpp
+++ b/layout/xul/base/src/nsListBoxBodyFrame.cpp
@@ -311,19 +311,18 @@ nsListBoxBodyFrame::AttributeChanged(PRI
       PRInt32 dummy;
       PRInt32 count = rows.ToInteger(&dummy);
       PRInt32 rowHeight = GetRowHeightAppUnits();
       rowHeight = nsPresContext::AppUnitsToIntCSSPixels(rowHeight);
       nsAutoString value;
       value.AppendInt(rowHeight*count);
       mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::minheight, value, PR_FALSE);
 
-      AddStateBits(NS_FRAME_IS_DIRTY);
       PresContext()->PresShell()->
-        FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+        FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     }
   }
   else
     rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 
   return rv;
  
 }
@@ -496,19 +495,18 @@ nsListBoxBodyFrame::ReflowFinished()
   if (mAdjustScroll) {
      VerticalScroll(mYPosition);
      mAdjustScroll = PR_FALSE;
   }
 
   // if the row height changed then mark everything as a style change. 
   // That will dirty the entire listbox
   if (mRowHeightWasSet) {
-    AddStateBits(NS_FRAME_IS_DIRTY);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+      FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
      PRInt32 pos = mCurrentIndex * mRowHeight;
      if (mYPosition != pos) 
        mAdjustScroll = PR_TRUE;
     mRowHeightWasSet = PR_FALSE;
   }
 
   mReflowCallbackPosted = PR_FALSE;
   return PR_TRUE;
@@ -925,19 +923,18 @@ nsListBoxBodyFrame::InternalPositionChan
     }
   }
 
   // clear frame markers so that CreateRows will re-create
   mTopFrame = mBottomFrame = nsnull; 
   
   mYPosition = mCurrentIndex*mRowHeight;
   mScrolling = PR_TRUE;
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eResize);
+    FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_HAS_DIRTY_CHILDREN);
   // Flush calls CreateRows
   // XXXbz there has to be a better way to do this than flushing!
   presContext->PresShell()->FlushPendingNotifications(Flush_OnlyReflow);
   mScrolling = PR_FALSE;
   
   VerticalScroll(mYPosition);
 
   PRTime end = PR_Now();
@@ -1055,19 +1052,19 @@ nsListBoxBodyFrame::DestroyRows(PRInt32&
     --aRowsToLose;
 
     nsIFrame* nextFrame = childFrame->GetNextSibling();
     RemoveChildFrame(state, childFrame);
 
     mTopFrame = childFrame = nextFrame;
   }
 
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                     NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
 void
 nsListBoxBodyFrame::ReverseDestroyRows(PRInt32& aRowsToLose) 
 {
   // We need to destroy frames until our row count has been properly
   // reduced.  A reflow will then pick up and create the new frames.
   nsIFrame* childFrame = GetLastFrame();
@@ -1078,19 +1075,19 @@ nsListBoxBodyFrame::ReverseDestroyRows(P
     
     nsIFrame* prevFrame;
     prevFrame = mFrames.GetPrevSiblingFor(childFrame);
     RemoveChildFrame(state, childFrame);
 
     mBottomFrame = childFrame = prevFrame;
   }
 
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                     NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
 //
 // Get the nsIBox for the first visible listitem, and if none exists,
 // create one.
 //
 nsIBox* 
 nsListBoxBodyFrame::GetFirstItemBox(PRInt32 aOffset, PRBool* aCreated)
@@ -1237,52 +1234,52 @@ nsListBoxBodyFrame::ContinueReflow(nscoo
       nsBoxLayoutState state(PresContext());
 
       while (currFrame) {
         nsIFrame* nextFrame = currFrame->GetNextSibling();
         RemoveChildFrame(state, currFrame);
         currFrame = nextFrame;
       }
 
-      AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
       PresContext()->PresShell()->
-        FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+        FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                         NS_FRAME_HAS_DIRTY_CHILDREN);
     }
     return PR_FALSE;
   }
   else
     return PR_TRUE;
 }
 
 NS_IMETHODIMP
 nsListBoxBodyFrame::ListBoxAppendFrames(nsIFrame* aFrameList)
 {
   // append them after
   nsBoxLayoutState state(PresContext());
   mFrames.AppendFrames(nsnull, aFrameList);
   if (mLayoutManager)
     mLayoutManager->ChildrenAppended(this, state, aFrameList);
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                     NS_FRAME_HAS_DIRTY_CHILDREN);
   
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsListBoxBodyFrame::ListBoxInsertFrames(nsIFrame* aPrevFrame, nsIFrame* aFrameList)
 {
   // insert the frames to our info list
   nsBoxLayoutState state(PresContext());
   mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
   if (mLayoutManager)
     mLayoutManager->ChildrenInserted(this, state, aPrevFrame, aFrameList);
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                     NS_FRAME_HAS_DIRTY_CHILDREN);
 
   return NS_OK;
 }
 
 // 
 // Called by nsCSSFrameConstructor when a new listitem content is inserted.
 //
 void 
@@ -1312,19 +1309,19 @@ nsListBoxBodyFrame::OnContentInserted(ns
     mRowsToPrepend = 1;
   } else if (nextSiblingContent) {
     // we may be inserting before a frame that is on screen
     nsIFrame* nextSiblingFrame = shell->GetPrimaryFrameFor(nextSiblingContent);
     mLinkupFrame = nextSiblingFrame;
   }
   
   CreateRows();
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                     NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
 // 
 // Called by nsCSSFrameConstructor when listitem content is removed.
 //
 void
 nsListBoxBodyFrame::OnContentRemoved(nsPresContext* aPresContext, nsIFrame* aChildFrame, PRInt32 aIndex)
 {
@@ -1385,19 +1382,19 @@ nsListBoxBodyFrame::OnContentRemoved(nsP
     mTopFrame = mTopFrame->GetNextSibling();
 
   // Go ahead and delete the frame.
   nsBoxLayoutState state(aPresContext);
   if (aChildFrame) {
     RemoveChildFrame(state, aChildFrame);
   }
 
-  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                     NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
 void
 nsListBoxBodyFrame::GetListItemContentAt(PRInt32 aIndex, nsIContent** aContent)
 {
   *aContent = nsnull;
   nsIContent* listboxContent = mContent->GetBindingParent();
   ENSURE_TRUE(listboxContent);
--- a/layout/xul/base/src/nsListBoxLayout.cpp
+++ b/layout/xul/base/src/nsListBoxLayout.cpp
@@ -200,17 +200,17 @@ nsListBoxLayout::LayoutInternal(nsIBox* 
     // If this box is dirty or if it has dirty children, we
     // call layout on it.
     nsRect childRect(box->GetRect());
     box->GetMargin(margin);
     
     // relayout if we must or we are dirty or some of our children are dirty
     //   or the client area is wider than us
     // XXXldb There should probably be a resize check here too!
-    if ((box->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) || childRect.width < clientRect.width) {
+    if (NS_SUBTREE_DIRTY(box) || childRect.width < clientRect.width) {
       childRect.x = 0;
       childRect.y = yOffset;
       childRect.width = clientRect.width;
       
       nsSize size = box->GetPrefSize(aState);
       body->SetRowHeight(size.height);
       
       childRect.height = rowHeight;
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -877,19 +877,19 @@ nsMenuFrame::OpenMenuInternal(PRBool aAc
       }
 
       // If the menu popup was not open, do a reflow.  This is either the
       // initial reflow for a brand-new popup, or a subsequent reflow for
       // a menu that was deactivated and needs to be brought back to its
       // active dimensions.
       if (!wasOpen)
       {
-         menuPopup->AddStateBits(NS_FRAME_IS_DIRTY);
          presContext->PresShell()->
-           FrameNeedsReflow(menuPopup, nsIPresShell::eStyleChange);
+           FrameNeedsReflow(menuPopup, nsIPresShell::eStyleChange,
+                            NS_FRAME_IS_DIRTY);
          presContext->PresShell()->FlushPendingNotifications(Flush_OnlyReflow);
       }
 
       nsRect curRect(menuPopup->GetRect());
       nsBoxLayoutState state(presContext);
       menuPopup->SetBounds(state, nsRect(0,0,mLastPref.width, mLastPref.height));
 
       nsIView* view = menuPopup->GetView();
@@ -898,19 +898,19 @@ nsMenuFrame::OpenMenuInternal(PRBool aAc
         vm->SetViewVisibility(view, nsViewVisibility_kHide);
       }
       menuPopup->SyncViewWithFrame(presContext, popupAnchor, popupAlign, this, -1, -1);
       nscoord newHeight = menuPopup->GetRect().height;
 
       // if the height is different then reflow. It might need scrollbars force a reflow
       if (curRect.height != newHeight || mLastPref.height != newHeight)
       {
-         menuPopup->AddStateBits(NS_FRAME_IS_DIRTY);
          presContext->PresShell()->
-           FrameNeedsReflow(menuPopup, nsIPresShell::eStyleChange);
+           FrameNeedsReflow(menuPopup, nsIPresShell::eStyleChange,
+                            NS_FRAME_IS_DIRTY);
          presContext->PresShell()->FlushPendingNotifications(Flush_OnlyReflow);
       }
 
       ActivateMenu(PR_TRUE);
       ENSURE_TRUE(weakFrame.IsAlive());
 
       nsIMenuParent *childPopup = nsnull;
       CallQueryInterface(frame, &childPopup);
@@ -1870,19 +1870,19 @@ NS_IMETHODIMP
 nsMenuFrame::RemoveFrame(nsIAtom*        aListName,
                          nsIFrame*       aOldFrame)
 {
   nsresult  rv;
 
   if (mPopupFrames.ContainsFrame(aOldFrame)) {
     // Go ahead and remove this frame.
     mPopupFrames.DestroyFrame(aOldFrame);
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN);
     rv = NS_OK;
   } else {
     rv = nsBoxFrame::RemoveFrame(aListName, aOldFrame);
   }
 
   return rv;
 }
 
@@ -1897,19 +1897,19 @@ nsMenuFrame::InsertFrames(nsIAtom*      
   if (aFrameList && NS_SUCCEEDED(CallQueryInterface(aFrameList, &menuPar))) {
     NS_ASSERTION(aFrameList->IsBoxFrame(),"Popup is not a box!!!");
     mPopupFrames.InsertFrames(nsnull, nsnull, aFrameList);
 
 #ifdef DEBUG_LAYOUT
     nsBoxLayoutState state(GetPresContext());
     SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
 #endif
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN);
     rv = NS_OK;
   } else {
     rv = nsBoxFrame::InsertFrames(aListName, aPrevFrame, aFrameList);  
   }
 
   return rv;
 }
 
@@ -1926,19 +1926,19 @@ nsMenuFrame::AppendFrames(nsIAtom*      
   if (aFrameList && NS_SUCCEEDED(CallQueryInterface(aFrameList, &menuPar))) {
     NS_ASSERTION(aFrameList->IsBoxFrame(),"Popup is not a box!!!");
 
     mPopupFrames.AppendFrames(nsnull, aFrameList);
 #ifdef DEBUG_LAYOUT
     nsBoxLayoutState state(GetPresContext());
     SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
 #endif
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN);
     rv = NS_OK;
   } else {
     rv = nsBoxFrame::AppendFrames(aListName, aFrameList); 
   }
 
   return rv;
 }
 
--- a/layout/xul/base/src/nsPopupSetFrame.cpp
+++ b/layout/xul/base/src/nsPopupSetFrame.cpp
@@ -575,18 +575,19 @@ nsPopupSetFrame::OpenPopup(nsPopupFrameL
 
     if (weakPopupFrame.IsAlive())
       ActivatePopup(aEntry, PR_FALSE);
 
     OnDestroyed(presContext, popupContent);
   }
 
   if (weakFrame.IsAlive()) {
-    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
-    PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    PresContext()->PresShell()->
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN);
   }
 }
 
 void
 nsPopupSetFrame::ActivatePopup(nsPopupFrameList* aEntry, PRBool aActivateFlag)
 {
   if (aEntry->mPopupContent) {
     // When we sync the popup view with the frame, we'll show the popup if |menutobedisplayed|
--- a/layout/xul/base/src/nsProgressMeterFrame.cpp
+++ b/layout/xul/base/src/nsProgressMeterFrame.cpp
@@ -113,19 +113,18 @@ nsProgressMeterFrame::AttributeChanged(P
     nsAutoString leftFlex, rightFlex;
     leftFlex.AppendInt(flex);
     rightFlex.AppendInt(remainder);
     nsWeakFrame weakFrame(this);
     barChild->GetContent()->SetAttr(kNameSpaceID_None, nsGkAtoms::flex, leftFlex, PR_TRUE);
     remainderContent->SetAttr(kNameSpaceID_None, nsGkAtoms::flex, rightFlex, PR_TRUE);
 
     if (weakFrame.IsAlive()) {
-      AddStateBits(NS_FRAME_IS_DIRTY);
       PresContext()->PresShell()->
-        FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+        FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
     }
   }
   return NS_OK;
 }
 
 #ifdef NS_DEBUG
 NS_IMETHODIMP
 nsProgressMeterFrame::GetFrameName(nsAString& aResult) const
--- a/layout/xul/base/src/nsSliderFrame.cpp
+++ b/layout/xul/base/src/nsSliderFrame.cpp
@@ -261,19 +261,18 @@ nsSliderFrame::AttributeChanged(PRInt32 
       }
   }
 
   if (aAttribute == nsGkAtoms::minpos ||
       aAttribute == nsGkAtoms::maxpos ||
       aAttribute == nsGkAtoms::pageincrement ||
       aAttribute == nsGkAtoms::increment) {
 
-      AddStateBits(NS_FRAME_IS_DIRTY);
       PresContext()->PresShell()->
-        FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+        FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsSliderFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
--- a/layout/xul/base/src/nsSplitterFrame.cpp
+++ b/layout/xul/base/src/nsSplitterFrame.cpp
@@ -603,18 +603,18 @@ nsSplitterFrameInner::MouseDrag(nsPresCo
         printf("before, index=%d, current=%d, changed=%d\n", mChildInfosBefore[i].index, mChildInfosBefore[i].current, mChildInfosBefore[i].changed);
       for (i=0; i < mChildInfosAfterCount; i++) 
         printf("after, index=%d, current=%d, changed=%d\n", mChildInfosAfter[i].index, mChildInfosAfter[i].current, mChildInfosAfter[i].changed);
     */
 
     /*
       nsIPresShell *shell = aPresContext->PresShell();
 
-      mOuter->mState |= NS_FRAME_IS_DIRTY;
-      shell->FrameNeedsReflow(mOuter, nsIPresShell::eStyleChange);
+      shell->FrameNeedsReflow(mOuter, nsIPresShell::eStyleChange,
+                              NS_FRAME_IS_DIRTY);
     */
     mDidDrag = PR_TRUE;
   }
 }
 
 void
 nsSplitterFrameInner::AddListener(nsPresContext* aPresContext)
 {
@@ -997,19 +997,18 @@ nsSplitterFrameInner::AdjustChildren(nsP
   
    // printf("----- Posting Dirty -----\n");
 
    
   if (realTimeDrag) {
     aPresContext->PresShell()->FlushPendingNotifications(Flush_Display);
   }
   else {
-    mOuter->AddStateBits(NS_FRAME_IS_DIRTY);
     aPresContext->PresShell()->
-      FrameNeedsReflow(mOuter, nsIPresShell::eTreeChange);
+      FrameNeedsReflow(mOuter, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
   }
 }
 
 static nsIBox* GetChildBoxForContent(nsIBox* aParentBox, nsIContent* aContent)
 {
   nsIBox* childBox = aParentBox->GetChildBox();
 
   while (nsnull != childBox) {
@@ -1095,18 +1094,18 @@ nsSplitterFrameInner::SetPreferredSize(n
   prefValue.AppendInt(pref/aOnePixel);
   if (content->AttrValueIs(kNameSpaceID_None, attribute,
                            prefValue, eCaseMatters))
      return;
 
   nsWeakFrame weakBox(aChildBox);
   content->SetAttr(kNameSpaceID_None, attribute, prefValue, PR_TRUE);
   ENSURE_TRUE(weakBox.IsAlive());
-  aChildBox->AddStateBits(NS_FRAME_IS_DIRTY);
-  aState.PresShell()->FrameNeedsReflow(aChildBox, nsIPresShell::eStyleChange);
+  aState.PresShell()->FrameNeedsReflow(aChildBox, nsIPresShell::eStyleChange,
+                                       NS_FRAME_IS_DIRTY);
 }
 
 
 void 
 nsSplitterFrameInner::AddRemoveSpace(nscoord aDiff,
                                     nsSplitterInfo* aChildInfos,
                                     PRInt32 aCount,
                                     PRInt32& aSpaceLeft)
--- a/layout/xul/base/src/nsSprocketLayout.cpp
+++ b/layout/xul/base/src/nsSprocketLayout.cpp
@@ -471,17 +471,17 @@ nsSprocketLayout::Layout(nsIBox* aBox, n
         childRect.height = 0;
 
       // Now we're trying to figure out if we have to lay out this child, i.e., to call
       // the child's Layout method.
       if (passes > 0) {
         layout = PR_FALSE;
       } else {
         // Always perform layout if we are dirty or have dirty children
-        if (!(child->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)))
+        if (!NS_SUBTREE_DIRTY(child))
           layout = PR_FALSE;
       }
 
       // We computed a childRect.  Now we want to set the bounds of the child to be that rect.
       // If our old rect is different, then we know our size changed and we cache that fact
       // in the |sizeChanged| variable.
       nsRect oldRect(child->GetRect());
       PRBool sizeChanged = PR_FALSE;
--- a/layout/xul/base/src/nsStackLayout.cpp
+++ b/layout/xul/base/src/nsStackLayout.cpp
@@ -262,17 +262,17 @@ nsStackLayout::Layout(nsIBox* aBox, nsBo
 
       if (childRect.height < 0)
         childRect.height = 0;
 
       nsRect oldRect(child->GetRect());
       PRBool sizeChanged = (oldRect != childRect);
 
       // only lay out dirty children or children whose sizes have changed
-      if (sizeChanged || (child->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
+      if (sizeChanged || NS_SUBTREE_DIRTY(child)) {
           // add in the child's margin
           nsMargin margin;
           child->GetMargin(margin);
 
           // obtain our offset from the top left border of the stack's content box.
           nsSize offset(0,0);
           PRBool offsetSpecified = AddOffset(aState, child, offset);
 
--- a/layout/xul/base/src/nsTextBoxFrame.cpp
+++ b/layout/xul/base/src/nsTextBoxFrame.cpp
@@ -118,19 +118,19 @@ nsTextBoxFrame::AttributeChanged(PRInt32
 {
     mState |= NS_STATE_NEED_LAYOUT;
     PRBool aResize;
     PRBool aRedraw;
 
     UpdateAttributes(aAttribute, aResize, aRedraw);
 
     if (aResize) {
-        AddStateBits(NS_FRAME_IS_DIRTY);
         PresContext()->PresShell()->
-          FrameNeedsReflow(this, nsIPresShell::eStyleChange);
+            FrameNeedsReflow(this, nsIPresShell::eStyleChange,
+                             NS_FRAME_IS_DIRTY);
     } else if (aRedraw) {
         nsBoxLayoutState state(PresContext());
         Redraw(state);
     }
 
     // If the accesskey changed, register for the new value
     // The old value has been unregistered in nsXULElement::SetAttr
     if (aAttribute == nsGkAtoms::accesskey || aAttribute == nsGkAtoms::control)
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
@@ -1725,18 +1725,19 @@ nsTreeBodyFrame::MarkDirtyIfSelect()
 
   if (baseElement && baseElement->Tag() == nsGkAtoms::select &&
       baseElement->IsNodeOfType(nsINode::eHTML)) {
     // If we are an intrinsically sized select widget, we may need to
     // resize, if the widest item was removed or a new item was added.
     // XXX optimize this more
 
     mStringWidth = -1;
-    AddStateBits(NS_FRAME_IS_DIRTY);
-    PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange);
+    PresContext()->PresShell()->FrameNeedsReflow(this,
+                                                 nsIPresShell::eTreeChange,
+                                                 NS_FRAME_IS_DIRTY);
   }
 }
 
 nsresult
 nsTreeBodyFrame::CreateTimer(const nsILookAndFeel::nsMetricID aID,
                              nsTimerCallbackFunc aFunc, PRInt32 aType,
                              nsITimer** aTimer)
 {
@@ -2689,19 +2690,18 @@ nsTreeBodyFrame::PaintTreeBody(nsIRender
   aRenderingContext.PushState();
   aRenderingContext.SetClipRect(mInnerBox + aPt, nsClipCombine_kIntersect);
   PRInt32 oldPageCount = mPageLength;
   if (!mHasFixedRowCount)
     mPageLength = mInnerBox.height/mRowHeight;
 
   if (oldPageCount != mPageLength || mHorzWidth != CalcHorzWidth(GetScrollParts())) {
     // Schedule a ResizeReflow that will update our info properly.
-    AddStateBits(NS_FRAME_IS_DIRTY);
     PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eResize);
+      FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
   }
   #ifdef DEBUG
   PRInt32 rowCount = mRowCount;
   mView->GetRowCount(&mRowCount);
   NS_ASSERTION(mRowCount == rowCount, "row count changed unexpectedly");
   #endif
 
   // Loop through our columns and paint them (e.g., for sorting).  This is only