Don't mark intrinsic widths dirty for font inflation width changes at box/block boundaries. (Bug 764354) r=bzbarsky
authorL. David Baron <dbaron@dbaron.org>
Wed, 13 Jun 2012 12:49:41 -0700
changeset 96573 e116a5da6cedfe7f980979005c5f4eaa4e0bfa4c
parent 96572 00244ceddd429edbf6c367b7e1710267db83eb73
child 96600 4f80d093ff2da516e70d303fbf4552435408f125
push id22918
push userdbaron@mozilla.com
push dateWed, 13 Jun 2012 19:50:05 +0000
treeherdermozilla-central@e116a5da6ced [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs764354
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Don't mark intrinsic widths dirty for font inflation width changes at box/block boundaries. (Bug 764354) r=bzbarsky
layout/generic/nsFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsHTMLReflowState.h
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -7635,17 +7635,18 @@ nsFrame::DoLayout(nsBoxLayoutState& aSta
   desiredSize.width = size.width;
   desiredSize.height = size.height;
   desiredSize.UnionOverflowAreasWithDesiredBounds();
 
   if (HasAbsolutelyPositionedChildren()) {
     // Set up a |reflowState| to pass into ReflowAbsoluteFrames
     nsHTMLReflowState reflowState(aState.PresContext(), this,
                                   aState.GetRenderingContext(),
-                                  nsSize(size.width, NS_UNCONSTRAINEDSIZE));
+                                  nsSize(size.width, NS_UNCONSTRAINEDSIZE),
+                                  nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
 
     // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
     // (just a dummy value; hopefully that's OK)
     nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
     ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
                          reflowState, reflowStatus);
   }
 
@@ -7740,17 +7741,18 @@ nsFrame::BoxReflow(nsBoxLayoutState&    
       parentSize.height += margin.TopBottom();
     if (parentSize.width != NS_INTRINSICSIZE)
       parentSize.width += margin.LeftRight();
 
     nsIFrame *parentFrame = GetParent();
     nsFrameState savedState = parentFrame->GetStateBits();
     nsHTMLReflowState parentReflowState(aPresContext, parentFrame,
                                         aRenderingContext,
-                                        parentSize);
+                                        parentSize,
+                                        nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
     parentFrame->RemoveStateBits(~nsFrameState(0));
     parentFrame->AddStateBits(savedState);
 
     // This may not do very much useful, but it's probably worth trying.
     if (parentSize.width != NS_INTRINSICSIZE)
       parentReflowState.SetComputedWidth(NS_MAX(parentSize.width, 0));
     if (parentSize.height != NS_INTRINSICSIZE)
       parentReflowState.SetComputedHeight(NS_MAX(parentSize.height, 0));
@@ -7760,17 +7762,18 @@ nsFrame::BoxReflow(nsBoxLayoutState&    
     parentFrame->GetBorder(parentReflowState.mComputedBorderPadding);
     parentReflowState.mComputedBorderPadding +=
       parentReflowState.mComputedPadding;
 
     // XXX Is it OK that this reflow state has no parent reflow state?
     // (It used to have a bogus parent, skipping all the boxes).
     nsSize availSize(aWidth, NS_INTRINSICSIZE);
     nsHTMLReflowState reflowState(aPresContext, this, aRenderingContext,
-                                  availSize);
+                                  availSize,
+                                  nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
 
     // Construct the parent chain manually since constructing it normally
     // messes up dimensions.
     const nsHTMLReflowState *outerReflowState = aState.OuterReflowState();
     NS_ASSERTION(!outerReflowState || outerReflowState->frame != this,
                  "in and out of XUL on a single frame?");
     if (outerReflowState && outerReflowState->frame == parentFrame) {
       // We're a frame (such as a text control frame) that jumps into
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -48,32 +48,38 @@ enum eNormalLineHeightControl {
 
 static eNormalLineHeightControl sNormalLineHeightControl = eUninitialized;
 
 // Initialize a <b>root</b> reflow state with a rendering context to
 // use for measuring things.
 nsHTMLReflowState::nsHTMLReflowState(nsPresContext*       aPresContext,
                                      nsIFrame*            aFrame,
                                      nsRenderingContext* aRenderingContext,
-                                     const nsSize&        aAvailableSpace)
+                                     const nsSize&        aAvailableSpace,
+                                     PRUint32             aFlags)
   : nsCSSOffsetState(aFrame, aRenderingContext)
   , mBlockDelta(0)
   , mReflowDepth(0)
 {
   NS_PRECONDITION(aPresContext, "no pres context");
   NS_PRECONDITION(aRenderingContext, "no rendering context");
   NS_PRECONDITION(aFrame, "no frame");
   parentReflowState = nsnull;
   availableWidth = aAvailableSpace.width;
   availableHeight = aAvailableSpace.height;
   mFloatManager = nsnull;
   mLineLayout = nsnull;
   memset(&mFlags, 0, sizeof(mFlags));
   mDiscoveredClearance = nsnull;
   mPercentHeightObserver = nsnull;
+
+  if (aFlags & DUMMY_PARENT_REFLOW_STATE) {
+    mFlags.mDummyParentReflowState = true;
+  }
+
   Init(aPresContext);
 }
 
 static bool CheckNextInFlowParenthood(nsIFrame* aFrame, nsIFrame* aParent)
 {
   nsIFrame* frameNext = aFrame->GetNextInFlow();
   nsIFrame* parentNext = aParent->GetNextInFlow();
   return frameNext && parentNext && frameNext->GetParent() == parentNext;
@@ -124,16 +130,17 @@ nsHTMLReflowState::nsHTMLReflowState(nsP
   // Note: mFlags was initialized as a copy of aParentReflowState.mFlags up in
   // this constructor's init list, so the only flags that we need to explicitly
   // initialize here are those that may need a value other than our parent's.
   mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
     CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
   mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false;
   mFlags.mHasClearance = false;
   mFlags.mIsColumnBalancing = false;
+  mFlags.mDummyParentReflowState = false;
 
   mDiscoveredClearance = nsnull;
   mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && 
                             aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) 
                            ? aParentReflowState.mPercentHeightObserver : nsnull;
 
   if (aInit) {
     Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight);
@@ -363,17 +370,23 @@ nsHTMLReflowState::InitResizeFlags(nsPre
 {
   bool isHResize = frame->GetSize().width !=
                      mComputedWidth + mComputedBorderPadding.LeftRight();
 
   if ((frame->GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) &&
       nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
     // Create our font inflation data if we don't have it already, and
     // give it our current width information.
-    bool dirty = nsFontInflationData::UpdateFontInflationDataWidthFor(*this);
+    bool dirty = nsFontInflationData::UpdateFontInflationDataWidthFor(*this) &&
+                 // Avoid running this at the box-to-block interface
+                 // (where we shouldn't be inflating anyway, and where
+                 // reflow state construction is probably to construct a
+                 // dummy parent reflow state anyway).
+                 !mFlags.mDummyParentReflowState;
+
     if (dirty || (!frame->GetParent() && isHResize)) {
       // When font size inflation is enabled, a change in either:
       //  * the effective width of a font inflation flow root
       //  * the width of the frame
       // needs to cause a dirty reflow since they change the font size
       // inflation calculations, which in turn change the size of text,
       // line-heights, etc.  This is relatively similar to a classic
       // case of style change reflow, except that because inflation
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -331,42 +331,51 @@ public:
                                      // (potentially) in a context where
                                      // percent heights have a different
                                      // basis?
     PRUint16 mTableIsSplittable:1;   // tables are splittable, this should happen only inside a page
                                      // and never insider a column frame
     PRUint16 mHeightDependsOnAncestorCell:1;   // Does frame height depend on
                                                // an ancestor table-cell?
     PRUint16 mIsColumnBalancing:1;   // nsColumnSetFrame is balancing columns
+    PRUint16 mDummyParentReflowState:1; // a "fake" reflow state made
+                                        // in order to be the parent
+                                        // of a real one
   } mFlags;
 
   // Note: The copy constructor is written by the compiler automatically. You
   // can use that and then override specific values if you want, or you can
   // call Init as desired...
 
   // Initialize a <b>root</b> reflow state with a rendering context to
   // use for measuring things.
   nsHTMLReflowState(nsPresContext*           aPresContext,
                     nsIFrame*                aFrame,
                     nsRenderingContext*     aRenderingContext,
-                    const nsSize&            aAvailableSpace);
+                    const nsSize&            aAvailableSpace,
+                    PRUint32                 aFlags = 0);
 
   // Initialize a reflow state for a child frames reflow. Some state
   // is copied from the parent reflow state; the remaining state is
   // computed. 
   nsHTMLReflowState(nsPresContext*           aPresContext,
                     const nsHTMLReflowState& aParentReflowState,
                     nsIFrame*                aFrame,
                     const nsSize&            aAvailableSpace,
                     // These two are used by absolute positioning code
                     // to override default containing block w & h:
                     nscoord                  aContainingBlockWidth = -1,
                     nscoord                  aContainingBlockHeight = -1,
                     bool                     aInit = true);
 
+  // Values for |aFlags| passed to constructor
+  enum {
+    DUMMY_PARENT_REFLOW_STATE = (1<<0)
+  };
+
   // This method initializes various data members. It is automatically
   // called by the various constructors
   void Init(nsPresContext* aPresContext,
             nscoord         aContainingBlockWidth = -1,
             nscoord         aContainingBlockHeight = -1,
             const nsMargin* aBorder = nsnull,
             const nsMargin* aPadding = nsnull);
   /**