layout/generic/nsHTMLReflowState.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /* struct containing the input to nsIFrame::Reflow */
     8 #include "nsHTMLReflowState.h"
    10 #include "nsStyleConsts.h"
    11 #include "nsCSSAnonBoxes.h"
    12 #include "nsFrame.h"
    13 #include "nsIContent.h"
    14 #include "nsGkAtoms.h"
    15 #include "nsPresContext.h"
    16 #include "nsIPresShell.h"
    17 #include "nsFontMetrics.h"
    18 #include "nsBlockFrame.h"
    19 #include "nsLineBox.h"
    20 #include "nsFlexContainerFrame.h"
    21 #include "nsImageFrame.h"
    22 #include "nsTableFrame.h"
    23 #include "nsTableCellFrame.h"
    24 #include "nsIPercentHeightObserver.h"
    25 #include "nsLayoutUtils.h"
    26 #include "mozilla/Preferences.h"
    27 #include "nsFontInflationData.h"
    28 #include "StickyScrollContainer.h"
    29 #include "nsIFrameInlines.h"
    30 #include <algorithm>
    31 #include "mozilla/dom/HTMLInputElement.h"
    33 #ifdef DEBUG
    34 #undef NOISY_VERTICAL_ALIGN
    35 #else
    36 #undef NOISY_VERTICAL_ALIGN
    37 #endif
    39 using namespace mozilla;
    40 using namespace mozilla::css;
    41 using namespace mozilla::dom;
    42 using namespace mozilla::layout;
    44 enum eNormalLineHeightControl {
    45   eUninitialized = -1,
    46   eNoExternalLeading = 0,   // does not include external leading 
    47   eIncludeExternalLeading,  // use whatever value font vendor provides
    48   eCompensateLeading        // compensate leading if leading provided by font vendor is not enough
    49 };
    51 static eNormalLineHeightControl sNormalLineHeightControl = eUninitialized;
    53 // Initialize a <b>root</b> reflow state with a rendering context to
    54 // use for measuring things.
    55 nsHTMLReflowState::nsHTMLReflowState(nsPresContext*       aPresContext,
    56                                      nsIFrame*            aFrame,
    57                                      nsRenderingContext*  aRenderingContext,
    58                                      const nsSize&        aAvailableSpace,
    59                                      uint32_t             aFlags)
    60   : nsCSSOffsetState(aFrame, aRenderingContext)
    61   , mBlockDelta(0)
    62   , mReflowDepth(0)
    63 {
    64   NS_PRECONDITION(aRenderingContext, "no rendering context");
    65   MOZ_ASSERT(aPresContext, "no pres context");
    66   MOZ_ASSERT(aFrame, "no frame");
    67   MOZ_ASSERT(aPresContext == aFrame->PresContext(), "wrong pres context");
    68   parentReflowState = nullptr;
    69   AvailableWidth() = aAvailableSpace.width;
    70   AvailableHeight() = aAvailableSpace.height;
    71   mFloatManager = nullptr;
    72   mLineLayout = nullptr;
    73   memset(&mFlags, 0, sizeof(mFlags));
    74   mDiscoveredClearance = nullptr;
    75   mPercentHeightObserver = nullptr;
    77   if (aFlags & DUMMY_PARENT_REFLOW_STATE) {
    78     mFlags.mDummyParentReflowState = true;
    79   }
    81   if (!(aFlags & CALLER_WILL_INIT)) {
    82     Init(aPresContext);
    83   }
    84 }
    86 static bool CheckNextInFlowParenthood(nsIFrame* aFrame, nsIFrame* aParent)
    87 {
    88   nsIFrame* frameNext = aFrame->GetNextInFlow();
    89   nsIFrame* parentNext = aParent->GetNextInFlow();
    90   return frameNext && parentNext && frameNext->GetParent() == parentNext;
    91 }
    93 /**
    94  * Adjusts the margin for a list (ol, ul), if necessary, depending on
    95  * font inflation settings. Unfortunately, because bullets from a list are
    96  * placed in the margin area, we only have ~40px in which to place the
    97  * bullets. When they are inflated, however, this causes problems, since
    98  * the text takes up more space than is available in the margin.
    99  *
   100  * This method will return a small amount (in app units) by which the
   101  * margin can be adjusted, so that the space is available for list
   102  * bullets to be rendered with font inflation enabled.
   103  */
   104 static  nscoord
   105 FontSizeInflationListMarginAdjustment(const nsIFrame* aFrame)
   106 {
   107   float inflation = nsLayoutUtils::FontSizeInflationFor(aFrame);
   108   if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
   109     const nsBlockFrame* blockFrame = static_cast<const nsBlockFrame*>(aFrame);
   110     const nsStyleList* styleList = aFrame->StyleList();
   112     // We only want to adjust the margins if we're dealing with an ordered
   113     // list.
   114     if (inflation > 1.0f &&
   115         blockFrame->HasBullet() &&
   116         styleList->mListStyleType != NS_STYLE_LIST_STYLE_NONE &&
   117         styleList->mListStyleType != NS_STYLE_LIST_STYLE_DISC &&
   118         styleList->mListStyleType != NS_STYLE_LIST_STYLE_CIRCLE &&
   119         styleList->mListStyleType != NS_STYLE_LIST_STYLE_SQUARE &&
   120         inflation > 1.0f) {
   122       // The HTML spec states that the default padding for ordered lists begins
   123       // at 40px, indicating that we have 40px of space to place a bullet. When
   124       // performing font inflation calculations, we add space equivalent to this,
   125       // but simply inflated at the same amount as the text, in app units.
   126       return nsPresContext::CSSPixelsToAppUnits(40) * (inflation - 1);
   127     }
   128   }
   130   return 0;
   131 }
   133 // NOTE: If we ever want to use nsCSSOffsetState for a flex item or a grid
   134 // item, we need to make it take the containing-block height as well as the
   135 // width, since flex items and grid items resolve vertical percent margins
   136 // and padding against the containing-block height, rather than its width.
   137 nsCSSOffsetState::nsCSSOffsetState(nsIFrame *aFrame,
   138                                    nsRenderingContext *aRenderingContext,
   139                                    nscoord aContainingBlockWidth)
   140   : frame(aFrame)
   141   , rendContext(aRenderingContext)
   142   , mWritingMode(aFrame->GetWritingMode())
   143 {
   144   MOZ_ASSERT(!aFrame->IsFlexItem(),
   145              "We're about to resolve vertical percent margin & padding "
   146              "values against CB width, which is incorrect for flex items");
   147   InitOffsets(aContainingBlockWidth, aContainingBlockWidth, frame->GetType());
   148 }
   150 // Initialize a reflow state for a child frame's reflow. Some state
   151 // is copied from the parent reflow state; the remaining state is
   152 // computed.
   153 nsHTMLReflowState::nsHTMLReflowState(nsPresContext*           aPresContext,
   154                                      const nsHTMLReflowState& aParentReflowState,
   155                                      nsIFrame*                aFrame,
   156                                      const nsSize&            aAvailableSpace,
   157                                      nscoord                  aContainingBlockWidth,
   158                                      nscoord                  aContainingBlockHeight,
   159                                      uint32_t                 aFlags)
   160   : nsCSSOffsetState(aFrame, aParentReflowState.rendContext)
   161   , mBlockDelta(0)
   162   , mReflowDepth(aParentReflowState.mReflowDepth + 1)
   163   , mFlags(aParentReflowState.mFlags)
   164 {
   165   MOZ_ASSERT(aPresContext, "no pres context");
   166   MOZ_ASSERT(aFrame, "no frame");
   167   MOZ_ASSERT(aPresContext == aFrame->PresContext(), "wrong pres context");
   168   NS_PRECONDITION((aContainingBlockWidth == -1) ==
   169                     (aContainingBlockHeight == -1),
   170                   "cb width and height should only be non-default together");
   171   NS_PRECONDITION(!mFlags.mSpecialHeightReflow ||
   172                   !NS_SUBTREE_DIRTY(aFrame),
   173                   "frame should be clean when getting special height reflow");
   175   parentReflowState = &aParentReflowState;
   177   // If the parent is dirty, then the child is as well.
   178   // XXX Are the other cases where the parent reflows a child a second
   179   // time, as a resize?
   180   if (!mFlags.mSpecialHeightReflow)
   181     frame->AddStateBits(parentReflowState->frame->GetStateBits() &
   182                         NS_FRAME_IS_DIRTY);
   184   AvailableWidth() = aAvailableSpace.width;
   185   AvailableHeight() = aAvailableSpace.height;
   187   mFloatManager = aParentReflowState.mFloatManager;
   188   if (frame->IsFrameOfType(nsIFrame::eLineParticipant))
   189     mLineLayout = aParentReflowState.mLineLayout;
   190   else
   191     mLineLayout = nullptr;
   193   // Note: mFlags was initialized as a copy of aParentReflowState.mFlags up in
   194   // this constructor's init list, so the only flags that we need to explicitly
   195   // initialize here are those that may need a value other than our parent's.
   196   mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
   197     CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
   198   mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false;
   199   mFlags.mHasClearance = false;
   200   mFlags.mIsColumnBalancing = false;
   201   mFlags.mIsFlexContainerMeasuringHeight = false;
   202   mFlags.mDummyParentReflowState = false;
   204   mDiscoveredClearance = nullptr;
   205   mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
   206                             aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
   207                            ? aParentReflowState.mPercentHeightObserver : nullptr;
   209   if (aFlags & DUMMY_PARENT_REFLOW_STATE) {
   210     mFlags.mDummyParentReflowState = true;
   211   }
   213   if (!(aFlags & CALLER_WILL_INIT)) {
   214     Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight);
   215   }
   216 }
   218 inline nscoord
   219 nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth,
   220                                     nscoord aContentEdgeToBoxSizing,
   221                                     nscoord aBoxSizingToMarginEdge,
   222                                     const nsStyleCoord& aCoord)
   223 {
   224   return nsLayoutUtils::ComputeWidthValue(rendContext, frame,
   225                                           aContainingBlockWidth,
   226                                           aContentEdgeToBoxSizing,
   227                                           aBoxSizingToMarginEdge,
   228                                           aCoord);
   229 }
   231 nscoord
   232 nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth,
   233                                     uint8_t aBoxSizing,
   234                                     const nsStyleCoord& aCoord)
   235 {
   236   nscoord inside = 0, outside = ComputedPhysicalBorderPadding().LeftRight() +
   237                                 ComputedPhysicalMargin().LeftRight();
   238   switch (aBoxSizing) {
   239     case NS_STYLE_BOX_SIZING_BORDER:
   240       inside = ComputedPhysicalBorderPadding().LeftRight();
   241       break;
   242     case NS_STYLE_BOX_SIZING_PADDING:
   243       inside = ComputedPhysicalPadding().LeftRight();
   244       break;
   245   }
   246   outside -= inside;
   248   return ComputeWidthValue(aContainingBlockWidth, inside,
   249                            outside, aCoord);
   250 }
   252 nscoord
   253 nsCSSOffsetState::ComputeHeightValue(nscoord aContainingBlockHeight,
   254                                      uint8_t aBoxSizing,
   255                                      const nsStyleCoord& aCoord)
   256 {
   257   nscoord inside = 0;
   258   switch (aBoxSizing) {
   259     case NS_STYLE_BOX_SIZING_BORDER:
   260       inside = ComputedPhysicalBorderPadding().TopBottom();
   261       break;
   262     case NS_STYLE_BOX_SIZING_PADDING:
   263       inside = ComputedPhysicalPadding().TopBottom();
   264       break;
   265   }
   266   return nsLayoutUtils::ComputeHeightValue(aContainingBlockHeight, 
   267                                            inside, aCoord);
   268 }
   270 void
   271 nsHTMLReflowState::SetComputedWidth(nscoord aComputedWidth)
   272 {
   273   NS_ASSERTION(frame, "Must have a frame!");
   274   // It'd be nice to assert that |frame| is not in reflow, but this fails for
   275   // two reasons:
   276   //
   277   // 1) Viewport frames reset the computed width on a copy of their reflow
   278   //    state when reflowing fixed-pos kids.  In that case we actually don't
   279   //    want to mess with the resize flags, because comparing the frame's rect
   280   //    to the munged computed width is pointless.
   281   // 2) nsFrame::BoxReflow creates a reflow state for its parent.  This reflow
   282   //    state is not used to reflow the parent, but just as a parent for the
   283   //    frame's own reflow state.  So given a nsBoxFrame inside some non-XUL
   284   //    (like a text control, for example), we'll end up creating a reflow
   285   //    state for the parent while the parent is reflowing.
   287   NS_PRECONDITION(aComputedWidth >= 0, "Invalid computed width");
   288   if (ComputedWidth() != aComputedWidth) {
   289     ComputedWidth() = aComputedWidth;
   290     nsIAtom* frameType = frame->GetType();
   291     if (frameType != nsGkAtoms::viewportFrame) { // Or check GetParent()?
   292       InitResizeFlags(frame->PresContext(), frameType);
   293     }
   294   }
   295 }
   297 void
   298 nsHTMLReflowState::SetComputedHeight(nscoord aComputedHeight)
   299 {
   300   NS_ASSERTION(frame, "Must have a frame!");
   301   // It'd be nice to assert that |frame| is not in reflow, but this fails
   302   // because:
   303   //
   304   //    nsFrame::BoxReflow creates a reflow state for its parent.  This reflow
   305   //    state is not used to reflow the parent, but just as a parent for the
   306   //    frame's own reflow state.  So given a nsBoxFrame inside some non-XUL
   307   //    (like a text control, for example), we'll end up creating a reflow
   308   //    state for the parent while the parent is reflowing.
   310   NS_PRECONDITION(aComputedHeight >= 0, "Invalid computed height");
   311   if (ComputedHeight() != aComputedHeight) {
   312     ComputedHeight() = aComputedHeight;
   313     InitResizeFlags(frame->PresContext(), frame->GetType());
   314   }
   315 }
   317 void
   318 nsHTMLReflowState::Init(nsPresContext* aPresContext,
   319                         nscoord         aContainingBlockWidth,
   320                         nscoord         aContainingBlockHeight,
   321                         const nsMargin* aBorder,
   322                         const nsMargin* aPadding)
   323 {
   324   NS_WARN_IF_FALSE(AvailableWidth() != NS_UNCONSTRAINEDSIZE,
   325                    "have unconstrained width; this should only result from "
   326                    "very large sizes, not attempts at intrinsic width "
   327                    "calculation");
   329   mStylePosition = frame->StylePosition();
   330   mStyleDisplay = frame->StyleDisplay();
   331   mStyleVisibility = frame->StyleVisibility();
   332   mStyleBorder = frame->StyleBorder();
   333   mStyleMargin = frame->StyleMargin();
   334   mStylePadding = frame->StylePadding();
   335   mStyleText = frame->StyleText();
   337   nsIAtom* type = frame->GetType();
   339   InitFrameType(type);
   340   InitCBReflowState();
   342   InitConstraints(aPresContext, aContainingBlockWidth, aContainingBlockHeight,
   343                   aBorder, aPadding, type);
   345   InitResizeFlags(aPresContext, type);
   347   nsIFrame *parent = frame->GetParent();
   348   if (parent &&
   349       (parent->GetStateBits() & NS_FRAME_IN_CONSTRAINED_HEIGHT) &&
   350       !(parent->GetType() == nsGkAtoms::scrollFrame &&
   351         parent->StyleDisplay()->mOverflowY != NS_STYLE_OVERFLOW_HIDDEN)) {
   352     frame->AddStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
   353   } else if (type == nsGkAtoms::svgForeignObjectFrame) {
   354     // An SVG foreignObject frame is inherently constrained height.
   355     frame->AddStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
   356   } else if ((mStylePosition->mHeight.GetUnit() != eStyleUnit_Auto ||
   357               mStylePosition->mMaxHeight.GetUnit() != eStyleUnit_None) &&
   358               // Don't set NS_FRAME_IN_CONSTRAINED_HEIGHT on body or html
   359               // elements.
   360              (frame->GetContent() &&
   361             !(frame->GetContent()->IsHTML(nsGkAtoms::body) ||
   362               frame->GetContent()->IsHTML(nsGkAtoms::html)))) {
   364     // If our height was specified as a percentage, then this could
   365     // actually resolve to 'auto', based on:
   366     // http://www.w3.org/TR/CSS21/visudet.html#the-height-property
   367     nsIFrame* containingBlk = frame;
   368     while (containingBlk) {
   369       const nsStylePosition* stylePos = containingBlk->StylePosition();
   370       if ((stylePos->mHeight.IsCoordPercentCalcUnit() &&
   371            !stylePos->mHeight.HasPercent()) ||
   372           (stylePos->mMaxHeight.IsCoordPercentCalcUnit() &&
   373            !stylePos->mMaxHeight.HasPercent())) {
   374         frame->AddStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
   375         break;
   376       } else if ((stylePos->mHeight.IsCoordPercentCalcUnit() &&
   377                   stylePos->mHeight.HasPercent()) ||
   378                  (stylePos->mMaxHeight.IsCoordPercentCalcUnit() &&
   379                   stylePos->mMaxHeight.HasPercent())) {
   380         if (!(containingBlk = containingBlk->GetContainingBlock())) {
   381           // If we've reached the top of the tree, then we don't have
   382           // a constrained height.
   383           frame->RemoveStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
   384           break;
   385         }
   387         continue;
   388       } else {
   389         frame->RemoveStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
   390         break;
   391       }
   392     }
   393   } else {
   394     frame->RemoveStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
   395   }
   397   NS_WARN_IF_FALSE((mFrameType == NS_CSS_FRAME_TYPE_INLINE &&
   398                     !frame->IsFrameOfType(nsIFrame::eReplaced)) ||
   399                    type == nsGkAtoms::textFrame ||
   400                    ComputedWidth() != NS_UNCONSTRAINEDSIZE,
   401                    "have unconstrained width; this should only result from "
   402                    "very large sizes, not attempts at intrinsic width "
   403                    "calculation");
   404 }
   406 void nsHTMLReflowState::InitCBReflowState()
   407 {
   408   if (!parentReflowState) {
   409     mCBReflowState = nullptr;
   410     return;
   411   }
   413   if (parentReflowState->frame == frame->GetContainingBlock()) {
   414     // Inner table frames need to use the containing block of the outer
   415     // table frame.
   416     if (frame->GetType() == nsGkAtoms::tableFrame) {
   417       mCBReflowState = parentReflowState->mCBReflowState;
   418     } else {
   419       mCBReflowState = parentReflowState;
   420     }
   421   } else {
   422     mCBReflowState = parentReflowState->mCBReflowState;
   423   }
   424 }
   426 /* Check whether CalcQuirkContainingBlockHeight would stop on the
   427  * given reflow state, using its block as a height.  (essentially 
   428  * returns false for any case in which CalcQuirkContainingBlockHeight 
   429  * has a "continue" in its main loop.)
   430  *
   431  * XXX Maybe refactor CalcQuirkContainingBlockHeight so it uses 
   432  * this function as well
   433  */
   434 static bool
   435 IsQuirkContainingBlockHeight(const nsHTMLReflowState* rs, nsIAtom* aFrameType)
   436 {
   437   if (nsGkAtoms::blockFrame == aFrameType ||
   438 #ifdef MOZ_XUL
   439       nsGkAtoms::XULLabelFrame == aFrameType ||
   440 #endif
   441       nsGkAtoms::scrollFrame == aFrameType) {
   442     // Note: This next condition could change due to a style change,
   443     // but that would cause a style reflow anyway, which means we're ok.
   444     if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
   445       if (!rs->frame->IsAbsolutelyPositioned()) {
   446         return false;
   447       }
   448     }
   449   }
   450   return true;
   451 }
   454 void
   455 nsHTMLReflowState::InitResizeFlags(nsPresContext* aPresContext, nsIAtom* aFrameType)
   456 {
   457   bool isHResize = (frame->GetSize().width !=
   458                      ComputedWidth() + ComputedPhysicalBorderPadding().LeftRight()) ||
   459                      aPresContext->PresShell()->IsReflowOnZoomPending();
   461   if ((frame->GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) &&
   462       nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
   463     // Create our font inflation data if we don't have it already, and
   464     // give it our current width information.
   465     bool dirty = nsFontInflationData::UpdateFontInflationDataWidthFor(*this) &&
   466                  // Avoid running this at the box-to-block interface
   467                  // (where we shouldn't be inflating anyway, and where
   468                  // reflow state construction is probably to construct a
   469                  // dummy parent reflow state anyway).
   470                  !mFlags.mDummyParentReflowState;
   472     if (dirty || (!frame->GetParent() && isHResize)) {
   473       // When font size inflation is enabled, a change in either:
   474       //  * the effective width of a font inflation flow root
   475       //  * the width of the frame
   476       // needs to cause a dirty reflow since they change the font size
   477       // inflation calculations, which in turn change the size of text,
   478       // line-heights, etc.  This is relatively similar to a classic
   479       // case of style change reflow, except that because inflation
   480       // doesn't affect the intrinsic sizing codepath, there's no need
   481       // to invalidate intrinsic sizes.
   482       //
   483       // Note that this makes horizontal resizing a good bit more
   484       // expensive.  However, font size inflation is targeted at a set of
   485       // devices (zoom-and-pan devices) where the main use case for
   486       // horizontal resizing needing to be efficient (window resizing) is
   487       // not present.  It does still increase the cost of dynamic changes
   488       // caused by script where a style or content change in one place
   489       // causes a resize in another (e.g., rebalancing a table).
   491       // FIXME: This isn't so great for the cases where
   492       // nsHTMLReflowState::SetComputedWidth is called, if the first time
   493       // we go through InitResizeFlags we set mHResize to true, and then
   494       // the second time we'd set it to false even without the
   495       // NS_FRAME_IS_DIRTY bit already set.
   496       if (frame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
   497         // Foreign object frames use dirty bits in a special way.
   498         frame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   499         nsIFrame *kid = frame->GetFirstPrincipalChild();
   500         if (kid) {
   501           kid->AddStateBits(NS_FRAME_IS_DIRTY);
   502         }
   503       } else {
   504         frame->AddStateBits(NS_FRAME_IS_DIRTY);
   505       }
   507       // Mark intrinsic widths on all descendants dirty.  We need to do
   508       // this (1) since we're changing the size of text and need to
   509       // clear text runs on text frames and (2) since we actually are
   510       // changing some intrinsic widths, but only those that live inside
   511       // of containers.
   513       // It makes sense to do this for descendants but not ancestors
   514       // (which is unusual) because we're only changing the unusual
   515       // inflation-dependent intrinsic widths (i.e., ones computed with
   516       // nsPresContext::mInflationDisabledForShrinkWrap set to false),
   517       // which should never affect anything outside of their inflation
   518       // flow root (or, for that matter, even their inflation
   519       // container).
   521       // This is also different from what PresShell::FrameNeedsReflow
   522       // does because it doesn't go through placeholders.  It doesn't
   523       // need to because we're actually doing something that cares about
   524       // frame tree geometry (the width on an ancestor) rather than
   525       // style.
   527       nsAutoTArray<nsIFrame*, 32> stack;
   528       stack.AppendElement(frame);
   530       do {
   531         nsIFrame *f = stack.ElementAt(stack.Length() - 1);
   532         stack.RemoveElementAt(stack.Length() - 1);
   534         nsIFrame::ChildListIterator lists(f);
   535         for (; !lists.IsDone(); lists.Next()) {
   536           nsFrameList::Enumerator childFrames(lists.CurrentList());
   537           for (; !childFrames.AtEnd(); childFrames.Next()) {
   538             nsIFrame* kid = childFrames.get();
   539             kid->MarkIntrinsicWidthsDirty();
   540             stack.AppendElement(kid);
   541           }
   542         }
   543       } while (stack.Length() != 0);
   544     }
   545   }
   547   mFlags.mHResize = !(frame->GetStateBits() & NS_FRAME_IS_DIRTY) &&
   548                     isHResize;
   550   // XXX Should we really need to null check mCBReflowState?  (We do for
   551   // at least nsBoxFrame).
   552   if (IS_TABLE_CELL(aFrameType) &&
   553       (mFlags.mSpecialHeightReflow ||
   554        (frame->FirstInFlow()->GetStateBits() &
   555          NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) &&
   556       (frame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
   557     // Need to set the bit on the cell so that
   558     // mCBReflowState->mFlags.mVResize is set correctly below when
   559     // reflowing descendant.
   560     mFlags.mVResize = true;
   561   } else if (mCBReflowState && !nsLayoutUtils::IsNonWrapperBlock(frame)) {
   562     // XXX Is this problematic for relatively positioned inlines acting
   563     // as containing block for absolutely positioned elements?
   564     // Possibly; in that case we should at least be checking
   565     // NS_SUBTREE_DIRTY, I'd think.
   566     mFlags.mVResize = mCBReflowState->mFlags.mVResize;
   567   } else if (ComputedHeight() == NS_AUTOHEIGHT) {
   568     if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
   569         mCBReflowState) {
   570       mFlags.mVResize = mCBReflowState->mFlags.mVResize;
   571     } else {
   572       mFlags.mVResize = mFlags.mHResize;
   573     }
   574     mFlags.mVResize = mFlags.mVResize || NS_SUBTREE_DIRTY(frame);
   575   } else {
   576     // not 'auto' height
   577     mFlags.mVResize = frame->GetSize().height !=
   578                         ComputedHeight() + ComputedPhysicalBorderPadding().TopBottom();
   579   }
   581   bool dependsOnCBHeight =
   582     (mStylePosition->HeightDependsOnContainer() &&
   583      // FIXME: condition this on not-abspos?
   584      mStylePosition->mHeight.GetUnit() != eStyleUnit_Auto) ||
   585     mStylePosition->MinHeightDependsOnContainer() ||
   586     mStylePosition->MaxHeightDependsOnContainer() ||
   587     mStylePosition->OffsetHasPercent(NS_SIDE_TOP) ||
   588     mStylePosition->mOffset.GetBottomUnit() != eStyleUnit_Auto ||
   589     frame->IsBoxFrame();
   591   if (mStyleText->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
   592     NS_ASSERTION(mStyleText->mLineHeight.GetIntValue() ==
   593                  NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT,
   594                  "bad line-height value");
   596     // line-height depends on block height
   597     frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
   598     // but only on containing blocks if this frame is not a suitable block
   599     dependsOnCBHeight |= !nsLayoutUtils::IsNonWrapperBlock(frame);
   600   }
   602   // If we're the descendant of a table cell that performs special height
   603   // reflows and we could be the child that requires them, always set
   604   // the vertical resize in case this is the first pass before the
   605   // special height reflow.  However, don't do this if it actually is
   606   // the special height reflow, since in that case it will already be
   607   // set correctly above if we need it set.
   608   if (!mFlags.mVResize && mCBReflowState &&
   609       (IS_TABLE_CELL(mCBReflowState->frame->GetType()) || 
   610        mCBReflowState->mFlags.mHeightDependsOnAncestorCell) &&
   611       !mCBReflowState->mFlags.mSpecialHeightReflow && 
   612       dependsOnCBHeight) {
   613     mFlags.mVResize = true;
   614     mFlags.mHeightDependsOnAncestorCell = true;
   615   }
   617   // Set NS_FRAME_CONTAINS_RELATIVE_HEIGHT if it's needed.
   619   // It would be nice to check that |mComputedHeight != NS_AUTOHEIGHT|
   620   // &&ed with the percentage height check.  However, this doesn't get
   621   // along with table special height reflows, since a special height
   622   // reflow (a quirk that makes such percentage heights work on children
   623   // of table cells) can cause not just a single percentage height to
   624   // become fixed, but an entire descendant chain of percentage heights
   625   // to become fixed.
   626   if (dependsOnCBHeight && mCBReflowState) {
   627     const nsHTMLReflowState *rs = this;
   628     bool hitCBReflowState = false;
   629     do {
   630       rs = rs->parentReflowState;
   631       if (!rs) {
   632         break;
   633       }
   635       if (rs->frame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)
   636         break; // no need to go further
   637       rs->frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
   639       // Keep track of whether we've hit the containing block, because
   640       // we need to go at least that far.
   641       if (rs == mCBReflowState) {
   642         hitCBReflowState = true;
   643       }
   645     } while (!hitCBReflowState ||
   646              (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
   647               !IsQuirkContainingBlockHeight(rs, rs->frame->GetType())));
   648     // Note: We actually don't need to set the
   649     // NS_FRAME_CONTAINS_RELATIVE_HEIGHT bit for the cases
   650     // where we hit the early break statements in
   651     // CalcQuirkContainingBlockHeight. But it doesn't hurt
   652     // us to set the bit in these cases.
   654   }
   655   if (frame->GetStateBits() & NS_FRAME_IS_DIRTY) {
   656     // If we're reflowing everything, then we'll find out if we need
   657     // to re-set this.
   658     frame->RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
   659   }
   660 }
   662 /* static */
   663 nscoord
   664 nsHTMLReflowState::GetContainingBlockContentWidth(const nsHTMLReflowState* aReflowState)
   665 {
   666   const nsHTMLReflowState* rs = aReflowState->mCBReflowState;
   667   if (!rs)
   668     return 0;
   669   return rs->ComputedWidth();
   670 }
   672 void
   673 nsHTMLReflowState::InitFrameType(nsIAtom* aFrameType)
   674 {
   675   const nsStyleDisplay *disp = mStyleDisplay;
   676   nsCSSFrameType frameType;
   678   // Section 9.7 of the CSS2 spec indicates that absolute position
   679   // takes precedence over float which takes precedence over display.
   680   // XXXldb nsRuleNode::ComputeDisplayData should take care of this, right?
   681   // Make sure the frame was actually moved out of the flow, and don't
   682   // just assume what the style says, because we might not have had a
   683   // useful float/absolute containing block
   685   DISPLAY_INIT_TYPE(frame, this);
   687   if (aFrameType == nsGkAtoms::tableFrame) {
   688     mFrameType = NS_CSS_FRAME_TYPE_BLOCK;
   689     return;
   690   }
   692   NS_ASSERTION(frame->StyleDisplay()->IsAbsolutelyPositionedStyle() ==
   693                  disp->IsAbsolutelyPositionedStyle(),
   694                "Unexpected position style");
   695   NS_ASSERTION(frame->StyleDisplay()->IsFloatingStyle() ==
   696                  disp->IsFloatingStyle(), "Unexpected float style");
   697   if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
   698     if (disp->IsAbsolutelyPositioned(frame)) {
   699       frameType = NS_CSS_FRAME_TYPE_ABSOLUTE;
   700       //XXXfr hack for making frames behave properly when in overflow container lists
   701       //      see bug 154892; need to revisit later
   702       if (frame->GetPrevInFlow())
   703         frameType = NS_CSS_FRAME_TYPE_BLOCK;
   704     }
   705     else if (disp->IsFloating(frame)) {
   706       frameType = NS_CSS_FRAME_TYPE_FLOATING;
   707     } else {
   708       NS_ASSERTION(disp->mDisplay == NS_STYLE_DISPLAY_POPUP,
   709                    "unknown out of flow frame type");
   710       frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
   711     }
   712   }
   713   else {
   714     switch (GetDisplay()) {
   715     case NS_STYLE_DISPLAY_BLOCK:
   716     case NS_STYLE_DISPLAY_LIST_ITEM:
   717     case NS_STYLE_DISPLAY_TABLE:
   718     case NS_STYLE_DISPLAY_TABLE_CAPTION:
   719     case NS_STYLE_DISPLAY_FLEX:
   720       frameType = NS_CSS_FRAME_TYPE_BLOCK;
   721       break;
   723     case NS_STYLE_DISPLAY_INLINE:
   724     case NS_STYLE_DISPLAY_INLINE_BLOCK:
   725     case NS_STYLE_DISPLAY_INLINE_TABLE:
   726     case NS_STYLE_DISPLAY_INLINE_BOX:
   727     case NS_STYLE_DISPLAY_INLINE_XUL_GRID:
   728     case NS_STYLE_DISPLAY_INLINE_STACK:
   729     case NS_STYLE_DISPLAY_INLINE_FLEX:
   730       frameType = NS_CSS_FRAME_TYPE_INLINE;
   731       break;
   733     case NS_STYLE_DISPLAY_TABLE_CELL:
   734     case NS_STYLE_DISPLAY_TABLE_ROW_GROUP:
   735     case NS_STYLE_DISPLAY_TABLE_COLUMN:
   736     case NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP:
   737     case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP:
   738     case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP:
   739     case NS_STYLE_DISPLAY_TABLE_ROW:
   740       frameType = NS_CSS_FRAME_TYPE_INTERNAL_TABLE;
   741       break;
   743     case NS_STYLE_DISPLAY_NONE:
   744     default:
   745       frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
   746       break;
   747     }
   748   }
   750   // See if the frame is replaced
   751   if (frame->IsFrameOfType(nsIFrame::eReplacedContainsBlock)) {
   752     frameType = NS_FRAME_REPLACED_CONTAINS_BLOCK(frameType);
   753   } else if (frame->IsFrameOfType(nsIFrame::eReplaced)) {
   754     frameType = NS_FRAME_REPLACED(frameType);
   755   }
   757   mFrameType = frameType;
   758 }
   760 /* static */ void
   761 nsHTMLReflowState::ComputeRelativeOffsets(uint8_t aCBDirection,
   762                                           nsIFrame* aFrame,
   763                                           nscoord aContainingBlockWidth,
   764                                           nscoord aContainingBlockHeight,
   765                                           nsMargin& aComputedOffsets)
   766 {
   767   const nsStylePosition* position = aFrame->StylePosition();
   769   // Compute the 'left' and 'right' values. 'Left' moves the boxes to the right,
   770   // and 'right' moves the boxes to the left. The computed values are always:
   771   // left=-right
   772   bool    leftIsAuto = eStyleUnit_Auto == position->mOffset.GetLeftUnit();
   773   bool    rightIsAuto = eStyleUnit_Auto == position->mOffset.GetRightUnit();
   775   // If neither 'left' not 'right' are auto, then we're over-constrained and
   776   // we ignore one of them
   777   if (!leftIsAuto && !rightIsAuto) {
   778     if (aCBDirection == NS_STYLE_DIRECTION_RTL) {
   779       leftIsAuto = true;
   780     } else {
   781       rightIsAuto = true;
   782     }
   783   }
   785   if (leftIsAuto) {
   786     if (rightIsAuto) {
   787       // If both are 'auto' (their initial values), the computed values are 0
   788       aComputedOffsets.left = aComputedOffsets.right = 0;
   789     } else {
   790       // 'Right' isn't 'auto' so compute its value
   791       aComputedOffsets.right = nsLayoutUtils::
   792         ComputeCBDependentValue(aContainingBlockWidth,
   793                                 position->mOffset.GetRight());
   795       // Computed value for 'left' is minus the value of 'right'
   796       aComputedOffsets.left = -aComputedOffsets.right;
   797     }
   799   } else {
   800     NS_ASSERTION(rightIsAuto, "unexpected specified constraint");
   802     // 'Left' isn't 'auto' so compute its value
   803     aComputedOffsets.left = nsLayoutUtils::
   804       ComputeCBDependentValue(aContainingBlockWidth,
   805                               position->mOffset.GetLeft());
   807     // Computed value for 'right' is minus the value of 'left'
   808     aComputedOffsets.right = -aComputedOffsets.left;
   809   }
   811   // Compute the 'top' and 'bottom' values. The 'top' and 'bottom' properties
   812   // move relatively positioned elements up and down. They also must be each 
   813   // other's negative
   814   bool    topIsAuto = eStyleUnit_Auto == position->mOffset.GetTopUnit();
   815   bool    bottomIsAuto = eStyleUnit_Auto == position->mOffset.GetBottomUnit();
   817   // Check for percentage based values and a containing block height that
   818   // depends on the content height. Treat them like 'auto'
   819   if (NS_AUTOHEIGHT == aContainingBlockHeight) {
   820     if (position->OffsetHasPercent(NS_SIDE_TOP)) {
   821       topIsAuto = true;
   822     }
   823     if (position->OffsetHasPercent(NS_SIDE_BOTTOM)) {
   824       bottomIsAuto = true;
   825     }
   826   }
   828   // If neither is 'auto', 'bottom' is ignored
   829   if (!topIsAuto && !bottomIsAuto) {
   830     bottomIsAuto = true;
   831   }
   833   if (topIsAuto) {
   834     if (bottomIsAuto) {
   835       // If both are 'auto' (their initial values), the computed values are 0
   836       aComputedOffsets.top = aComputedOffsets.bottom = 0;
   837     } else {
   838       // 'Bottom' isn't 'auto' so compute its value
   839       aComputedOffsets.bottom = nsLayoutUtils::
   840         ComputeHeightDependentValue(aContainingBlockHeight,
   841                                     position->mOffset.GetBottom());
   843       // Computed value for 'top' is minus the value of 'bottom'
   844       aComputedOffsets.top = -aComputedOffsets.bottom;
   845     }
   847   } else {
   848     NS_ASSERTION(bottomIsAuto, "unexpected specified constraint");
   850     // 'Top' isn't 'auto' so compute its value
   851     aComputedOffsets.top = nsLayoutUtils::
   852       ComputeHeightDependentValue(aContainingBlockHeight,
   853                                   position->mOffset.GetTop());
   855     // Computed value for 'bottom' is minus the value of 'top'
   856     aComputedOffsets.bottom = -aComputedOffsets.top;
   857   }
   859   // Store the offset
   860   FrameProperties props = aFrame->Properties();
   861   nsMargin* offsets = static_cast<nsMargin*>
   862     (props.Get(nsIFrame::ComputedOffsetProperty()));
   863   if (offsets) {
   864     *offsets = aComputedOffsets;
   865   } else {
   866     props.Set(nsIFrame::ComputedOffsetProperty(),
   867               new nsMargin(aComputedOffsets));
   868   }
   869 }
   871 /* static */ void
   872 nsHTMLReflowState::ApplyRelativePositioning(nsIFrame* aFrame,
   873                                             const nsMargin& aComputedOffsets,
   874                                             nsPoint* aPosition)
   875 {
   876   if (!aFrame->IsRelativelyPositioned()) {
   877     NS_ASSERTION(!aFrame->Properties().Get(nsIFrame::NormalPositionProperty()),
   878                  "We assume that changing the 'position' property causes "
   879                  "frame reconstruction.  If that ever changes, this code "
   880                  "should call "
   881                  "props.Delete(nsIFrame::NormalPositionProperty())");
   882     return;
   883   }
   885   // Store the normal position
   886   FrameProperties props = aFrame->Properties();
   887   nsPoint* normalPosition = static_cast<nsPoint*>
   888     (props.Get(nsIFrame::NormalPositionProperty()));
   889   if (normalPosition) {
   890     *normalPosition = *aPosition;
   891   } else {
   892     props.Set(nsIFrame::NormalPositionProperty(), new nsPoint(*aPosition));
   893   }
   895   const nsStyleDisplay* display = aFrame->StyleDisplay();
   896   if (NS_STYLE_POSITION_RELATIVE == display->mPosition) {
   897     *aPosition += nsPoint(aComputedOffsets.left, aComputedOffsets.top);
   898   } else if (NS_STYLE_POSITION_STICKY == display->mPosition &&
   899              !aFrame->GetNextContinuation() &&
   900              !aFrame->GetPrevContinuation() &&
   901              !(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
   902     // Sticky positioning for elements with multiple frames needs to be
   903     // computed all at once. We can't safely do that here because we might be
   904     // partway through (re)positioning the frames, so leave it until the scroll
   905     // container reflows and calls StickyScrollContainer::UpdatePositions.
   906     // For single-frame sticky positioned elements, though, go ahead and apply
   907     // it now to avoid unnecessary overflow updates later.
   908     StickyScrollContainer* ssc =
   909       StickyScrollContainer::GetStickyScrollContainerForFrame(aFrame);
   910     if (ssc) {
   911       *aPosition = ssc->ComputePosition(aFrame);
   912     }
   913   }
   914 }
   916 nsIFrame*
   917 nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame* aFrame,
   918                                                nscoord& aCBLeftEdge,
   919                                                nscoord& aCBWidth)
   920 {
   921   aFrame = aFrame->GetContainingBlock();
   922   NS_ASSERTION(aFrame != frame, "How did that happen?");
   924   /* Now aFrame is the containing block we want */
   926   /* Check whether the containing block is currently being reflowed.
   927      If so, use the info from the reflow state. */
   928   const nsHTMLReflowState* state;
   929   if (aFrame->GetStateBits() & NS_FRAME_IN_REFLOW) {
   930     for (state = parentReflowState; state && state->frame != aFrame;
   931          state = state->parentReflowState) {
   932       /* do nothing */
   933     }
   934   } else {
   935     state = nullptr;
   936   }
   938   if (state) {
   939     aCBLeftEdge = state->ComputedPhysicalBorderPadding().left;
   940     aCBWidth = state->ComputedWidth();
   941   } else {
   942     /* Didn't find a reflow state for aFrame.  Just compute the information we
   943        want, on the assumption that aFrame already knows its size.  This really
   944        ought to be true by now. */
   945     NS_ASSERTION(!(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW),
   946                  "aFrame shouldn't be in reflow; we'll lie if it is");
   947     nsMargin borderPadding = aFrame->GetUsedBorderAndPadding();
   948     aCBLeftEdge = borderPadding.left;
   949     aCBWidth = aFrame->GetSize().width - borderPadding.LeftRight();
   950   }
   952   return aFrame;
   953 }
   955 // When determining the hypothetical box that would have been if the element
   956 // had been in the flow we may not be able to exactly determine both the left
   957 // and right edges. For example, if the element is a non-replaced inline-level
   958 // element we would have to reflow it in order to determine it desired width.
   959 // In that case depending on the progression direction either the left or
   960 // right edge would be marked as not being exact
   961 struct nsHypotheticalBox {
   962   // offsets from left edge of containing block (which is a padding edge)
   963   nscoord       mLeft, mRight;
   964   // offset from top edge of containing block (which is a padding edge)
   965   nscoord       mTop;
   966 #ifdef DEBUG
   967   bool          mLeftIsExact, mRightIsExact;
   968 #endif
   970   nsHypotheticalBox() {
   971 #ifdef DEBUG
   972     mLeftIsExact = mRightIsExact = false;
   973 #endif
   974   }
   975 };
   977 static bool
   978 GetIntrinsicSizeFor(nsIFrame* aFrame, nsSize& aIntrinsicSize, nsIAtom* aFrameType)
   979 {
   980   // See if it is an image frame
   981   bool success = false;
   983   // Currently the only type of replaced frame that we can get the intrinsic
   984   // size for is an image frame
   985   // XXX We should add back the GetReflowMetrics() function and one of the
   986   // things should be the intrinsic size...
   987   if (aFrameType == nsGkAtoms::imageFrame) {
   988     nsImageFrame* imageFrame = (nsImageFrame*)aFrame;
   990     if (NS_SUCCEEDED(imageFrame->GetIntrinsicImageSize(aIntrinsicSize))) {
   991       success = (aIntrinsicSize != nsSize(0, 0));
   992     }
   993   }
   994   return success;
   995 }
   997 /**
   998  * aInsideBoxSizing returns the part of the horizontal padding, border,
   999  * and margin that goes inside the edge given by box-sizing;
  1000  * aOutsideBoxSizing returns the rest.
  1001  */
  1002 void
  1003 nsHTMLReflowState::CalculateHorizBorderPaddingMargin(
  1004                        nscoord aContainingBlockWidth,
  1005                        nscoord* aInsideBoxSizing,
  1006                        nscoord* aOutsideBoxSizing)
  1008   const nsMargin& border = mStyleBorder->GetComputedBorder();
  1009   nsMargin padding, margin;
  1011   // See if the style system can provide us the padding directly
  1012   if (!mStylePadding->GetPadding(padding)) {
  1013     // We have to compute the left and right values
  1014     padding.left = nsLayoutUtils::
  1015       ComputeCBDependentValue(aContainingBlockWidth,
  1016                               mStylePadding->mPadding.GetLeft());
  1017     padding.right = nsLayoutUtils::
  1018       ComputeCBDependentValue(aContainingBlockWidth,
  1019                               mStylePadding->mPadding.GetRight());
  1022   // See if the style system can provide us the margin directly
  1023   if (!mStyleMargin->GetMargin(margin)) {
  1024     // We have to compute the left and right values
  1025     if (eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit()) {
  1026       // XXX FIXME (or does CalculateBlockSideMargins do this?)
  1027       margin.left = 0;  // just ignore
  1028     } else {
  1029       margin.left = nsLayoutUtils::
  1030         ComputeCBDependentValue(aContainingBlockWidth,
  1031                                 mStyleMargin->mMargin.GetLeft());
  1033     if (eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit()) {
  1034       // XXX FIXME (or does CalculateBlockSideMargins do this?)
  1035       margin.right = 0;  // just ignore
  1036     } else {
  1037       margin.right = nsLayoutUtils::
  1038         ComputeCBDependentValue(aContainingBlockWidth,
  1039                                 mStyleMargin->mMargin.GetRight());
  1043   nscoord outside =
  1044     padding.LeftRight() + border.LeftRight() + margin.LeftRight();
  1045   nscoord inside = 0;
  1046   switch (mStylePosition->mBoxSizing) {
  1047     case NS_STYLE_BOX_SIZING_BORDER:
  1048       inside += border.LeftRight();
  1049       // fall through
  1050     case NS_STYLE_BOX_SIZING_PADDING:
  1051       inside += padding.LeftRight();
  1053   outside -= inside;
  1054   *aInsideBoxSizing = inside;
  1055   *aOutsideBoxSizing = outside;
  1056   return;
  1059 /**
  1060  * Returns true iff a pre-order traversal of the normal child
  1061  * frames rooted at aFrame finds no non-empty frame before aDescendant.
  1062  */
  1063 static bool AreAllEarlierInFlowFramesEmpty(nsIFrame* aFrame,
  1064   nsIFrame* aDescendant, bool* aFound) {
  1065   if (aFrame == aDescendant) {
  1066     *aFound = true;
  1067     return true;
  1069   if (!aFrame->IsSelfEmpty()) {
  1070     *aFound = false;
  1071     return false;
  1073   for (nsIFrame* f = aFrame->GetFirstPrincipalChild(); f; f = f->GetNextSibling()) {
  1074     bool allEmpty = AreAllEarlierInFlowFramesEmpty(f, aDescendant, aFound);
  1075     if (*aFound || !allEmpty) {
  1076       return allEmpty;
  1079   *aFound = false;
  1080   return true;
  1083 // Calculate the hypothetical box that the element would have if it were in
  1084 // the flow. The values returned are relative to the padding edge of the
  1085 // absolute containing block
  1086 // aContainingBlock is the placeholder's containing block (XXX rename it?)
  1087 // cbrs->frame is the actual containing block
  1088 void
  1089 nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext*    aPresContext,
  1090                                             nsIFrame*         aPlaceholderFrame,
  1091                                             nsIFrame*         aContainingBlock,
  1092                                             nscoord           aBlockLeftContentEdge,
  1093                                             nscoord           aBlockContentWidth,
  1094                                             const nsHTMLReflowState* cbrs,
  1095                                             nsHypotheticalBox& aHypotheticalBox,
  1096                                             nsIAtom*          aFrameType)
  1098   NS_ASSERTION(mStyleDisplay->mOriginalDisplay != NS_STYLE_DISPLAY_NONE,
  1099                "mOriginalDisplay has not been properly initialized");
  1101   // If it's a replaced element and it has a 'auto' value for 'width', see if we
  1102   // can get the intrinsic size. This will allow us to exactly determine both the
  1103   // left and right edges
  1104   bool isAutoWidth = mStylePosition->mWidth.GetUnit() == eStyleUnit_Auto;
  1105   nsSize      intrinsicSize;
  1106   bool        knowIntrinsicSize = false;
  1107   if (NS_FRAME_IS_REPLACED(mFrameType) && isAutoWidth) {
  1108     // See if we can get the intrinsic size of the element
  1109     knowIntrinsicSize = GetIntrinsicSizeFor(frame, intrinsicSize, aFrameType);
  1112   // See if we can calculate what the box width would have been if the
  1113   // element had been in the flow
  1114   nscoord boxWidth;
  1115   bool    knowBoxWidth = false;
  1116   if ((NS_STYLE_DISPLAY_INLINE == mStyleDisplay->mOriginalDisplay) &&
  1117       !NS_FRAME_IS_REPLACED(mFrameType)) {
  1118     // For non-replaced inline-level elements the 'width' property doesn't apply,
  1119     // so we don't know what the width would have been without reflowing it
  1121   } else {
  1122     // It's either a replaced inline-level element or a block-level element
  1124     // Determine the total amount of horizontal border/padding/margin that
  1125     // the element would have had if it had been in the flow. Note that we
  1126     // ignore any 'auto' and 'inherit' values
  1127     nscoord insideBoxSizing, outsideBoxSizing;
  1128     CalculateHorizBorderPaddingMargin(aBlockContentWidth,
  1129                                       &insideBoxSizing, &outsideBoxSizing);
  1131     if (NS_FRAME_IS_REPLACED(mFrameType) && isAutoWidth) {
  1132       // It's a replaced element with an 'auto' width so the box width is
  1133       // its intrinsic size plus any border/padding/margin
  1134       if (knowIntrinsicSize) {
  1135         boxWidth = intrinsicSize.width + outsideBoxSizing + insideBoxSizing;
  1136         knowBoxWidth = true;
  1139     } else if (isAutoWidth) {
  1140       // The box width is the containing block width
  1141       boxWidth = aBlockContentWidth;
  1142       knowBoxWidth = true;
  1144     } else {
  1145       // We need to compute it. It's important we do this, because if it's
  1146       // percentage based this computed value may be different from the computed
  1147       // value calculated using the absolute containing block width
  1148       boxWidth = ComputeWidthValue(aBlockContentWidth,
  1149                                    insideBoxSizing, outsideBoxSizing,
  1150                                    mStylePosition->mWidth) + 
  1151                  insideBoxSizing + outsideBoxSizing;
  1152       knowBoxWidth = true;
  1156   // Get the 'direction' of the block
  1157   const nsStyleVisibility* blockVis = aContainingBlock->StyleVisibility();
  1159   // Get the placeholder x-offset and y-offset in the coordinate
  1160   // space of its containing block
  1161   // XXXbz the placeholder is not fully reflowed yet if our containing block is
  1162   // relatively positioned...
  1163   nsPoint placeholderOffset = aPlaceholderFrame->GetOffsetTo(aContainingBlock);
  1165   // First, determine the hypothetical box's mTop.  We want to check the
  1166   // content insertion frame of aContainingBlock for block-ness, but make
  1167   // sure to compute all coordinates in the coordinate system of
  1168   // aContainingBlock.
  1169   nsBlockFrame* blockFrame =
  1170     nsLayoutUtils::GetAsBlock(aContainingBlock->GetContentInsertionFrame());
  1171   if (blockFrame) {
  1172     nscoord blockYOffset = blockFrame->GetOffsetTo(aContainingBlock).y;
  1173     bool isValid;
  1174     nsBlockInFlowLineIterator iter(blockFrame, aPlaceholderFrame, &isValid);
  1175     if (!isValid) {
  1176       // Give up.  We're probably dealing with somebody using
  1177       // position:absolute inside native-anonymous content anyway.
  1178       aHypotheticalBox.mTop = placeholderOffset.y;
  1179     } else {
  1180       NS_ASSERTION(iter.GetContainer() == blockFrame,
  1181                    "Found placeholder in wrong block!");
  1182       nsBlockFrame::line_iterator lineBox = iter.GetLine();
  1184       // How we determine the hypothetical box depends on whether the element
  1185       // would have been inline-level or block-level
  1186       if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) {
  1187         // Use the top of the inline box which the placeholder lives in
  1188         // as the hypothetical box's top.
  1189         aHypotheticalBox.mTop = lineBox->GetPhysicalBounds().y + blockYOffset;
  1190       } else {
  1191         // The element would have been block-level which means it would
  1192         // be below the line containing the placeholder frame, unless
  1193         // all the frames before it are empty.  In that case, it would
  1194         // have been just before this line.
  1195         // XXXbz the line box is not fully reflowed yet if our
  1196         // containing block is relatively positioned...
  1197         if (lineBox != iter.End()) {
  1198           nsIFrame * firstFrame = lineBox->mFirstChild;
  1199           bool found = false;
  1200           bool allEmpty = true;
  1201           while (firstFrame) { // See bug 223064
  1202             allEmpty = AreAllEarlierInFlowFramesEmpty(firstFrame,
  1203               aPlaceholderFrame, &found);
  1204             if (found || !allEmpty)
  1205               break;
  1206             firstFrame = firstFrame->GetNextSibling();
  1208           NS_ASSERTION(firstFrame, "Couldn't find placeholder!");
  1210           if (allEmpty) {
  1211             // The top of the hypothetical box is the top of the line
  1212             // containing the placeholder, since there is nothing in the
  1213             // line before our placeholder except empty frames.
  1214             aHypotheticalBox.mTop = lineBox->GetPhysicalBounds().y + blockYOffset;
  1215           } else {
  1216             // The top of the hypothetical box is just below the line
  1217             // containing the placeholder.
  1218             aHypotheticalBox.mTop = lineBox->GetPhysicalBounds().YMost() + blockYOffset;
  1220         } else {
  1221           // Just use the placeholder's y-offset wrt the containing block
  1222           aHypotheticalBox.mTop = placeholderOffset.y;
  1226   } else {
  1227     // The containing block is not a block, so it's probably something
  1228     // like a XUL box, etc.
  1229     // Just use the placeholder's y-offset
  1230     aHypotheticalBox.mTop = placeholderOffset.y;
  1233   // Second, determine the hypothetical box's mLeft & mRight
  1234   // To determine the left and right offsets we need to look at the block's 'direction'
  1235   if (NS_STYLE_DIRECTION_LTR == blockVis->mDirection) {
  1236     // How we determine the hypothetical box depends on whether the element
  1237     // would have been inline-level or block-level
  1238     if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) {
  1239       // The placeholder represents the left edge of the hypothetical box
  1240       aHypotheticalBox.mLeft = placeholderOffset.x;
  1241     } else {
  1242       aHypotheticalBox.mLeft = aBlockLeftContentEdge;
  1244 #ifdef DEBUG
  1245     aHypotheticalBox.mLeftIsExact = true;
  1246 #endif
  1248     if (knowBoxWidth) {
  1249       aHypotheticalBox.mRight = aHypotheticalBox.mLeft + boxWidth;
  1250 #ifdef DEBUG
  1251       aHypotheticalBox.mRightIsExact = true;
  1252 #endif
  1253     } else {
  1254       // We can't compute the right edge because we don't know the desired
  1255       // width. So instead use the right content edge of the block parent,
  1256       // but remember it's not exact
  1257       aHypotheticalBox.mRight = aBlockLeftContentEdge + aBlockContentWidth;
  1258 #ifdef DEBUG
  1259       aHypotheticalBox.mRightIsExact = false;
  1260 #endif
  1263   } else {
  1264     // The placeholder represents the right edge of the hypothetical box
  1265     if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) {
  1266       aHypotheticalBox.mRight = placeholderOffset.x;
  1267     } else {
  1268       aHypotheticalBox.mRight = aBlockLeftContentEdge + aBlockContentWidth;
  1270 #ifdef DEBUG
  1271     aHypotheticalBox.mRightIsExact = true;
  1272 #endif
  1274     if (knowBoxWidth) {
  1275       aHypotheticalBox.mLeft = aHypotheticalBox.mRight - boxWidth;
  1276 #ifdef DEBUG
  1277       aHypotheticalBox.mLeftIsExact = true;
  1278 #endif
  1279     } else {
  1280       // We can't compute the left edge because we don't know the desired
  1281       // width. So instead use the left content edge of the block parent,
  1282       // but remember it's not exact
  1283       aHypotheticalBox.mLeft = aBlockLeftContentEdge;
  1284 #ifdef DEBUG
  1285       aHypotheticalBox.mLeftIsExact = false;
  1286 #endif
  1291   // The current coordinate space is that of the nearest block to the placeholder.
  1292   // Convert to the coordinate space of the absolute containing block
  1293   // One weird thing here is that for fixed-positioned elements we want to do
  1294   // the conversion incorrectly; specifically we want to ignore any scrolling
  1295   // that may have happened;
  1296   nsPoint cbOffset;
  1297   if (mStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED &&
  1298       // Exclude cases inside -moz-transform where fixed is like absolute.
  1299       nsLayoutUtils::IsReallyFixedPos(frame)) {
  1300     // In this case, cbrs->frame will always be an ancestor of
  1301     // aContainingBlock, so can just walk our way up the frame tree.
  1302     // Make sure to not add positions of frames whose parent is a
  1303     // scrollFrame, since we're doing fixed positioning, which assumes
  1304     // everything is scrolled to (0,0).
  1305     cbOffset.MoveTo(0, 0);
  1306     do {
  1307       NS_ASSERTION(aContainingBlock,
  1308                    "Should hit cbrs->frame before we run off the frame tree!");
  1309       cbOffset += aContainingBlock->GetPositionIgnoringScrolling();
  1310       aContainingBlock = aContainingBlock->GetParent();
  1311     } while (aContainingBlock != cbrs->frame);
  1312   } else {
  1313     // XXXldb We need to either ignore scrolling for the absolute
  1314     // positioning case too (and take the incompatibility) or figure out
  1315     // how to make these positioned elements actually *move* when we
  1316     // scroll, and thus avoid the resulting incremental reflow bugs.
  1317     cbOffset = aContainingBlock->GetOffsetTo(cbrs->frame);
  1319   aHypotheticalBox.mLeft += cbOffset.x;
  1320   aHypotheticalBox.mTop += cbOffset.y;
  1321   aHypotheticalBox.mRight += cbOffset.x;
  1323   // The specified offsets are relative to the absolute containing block's
  1324   // padding edge and our current values are relative to the border edge, so
  1325   // translate.
  1326   nsMargin border = cbrs->ComputedPhysicalBorderPadding() - cbrs->ComputedPhysicalPadding();
  1327   aHypotheticalBox.mLeft -= border.left;
  1328   aHypotheticalBox.mRight -= border.left;
  1329   aHypotheticalBox.mTop -= border.top;
  1332 void
  1333 nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext* aPresContext,
  1334                                            const nsHTMLReflowState* cbrs,
  1335                                            nscoord containingBlockWidth,
  1336                                            nscoord containingBlockHeight,
  1337                                            nsIAtom* aFrameType)
  1339   NS_PRECONDITION(containingBlockHeight != NS_AUTOHEIGHT,
  1340                   "containing block height must be constrained");
  1342   NS_ASSERTION(aFrameType != nsGkAtoms::tableFrame,
  1343                "InitAbsoluteConstraints should not be called on table frames");
  1344   NS_ASSERTION(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
  1345                "Why are we here?");
  1347   // Get the placeholder frame
  1348   nsIFrame*     placeholderFrame;
  1350   placeholderFrame = aPresContext->PresShell()->GetPlaceholderFrameFor(frame);
  1351   NS_ASSERTION(nullptr != placeholderFrame, "no placeholder frame");
  1353   // If both 'left' and 'right' are 'auto' or both 'top' and 'bottom' are
  1354   // 'auto', then compute the hypothetical box of where the element would
  1355   // have been if it had been in the flow
  1356   nsHypotheticalBox hypotheticalBox;
  1357   if (((eStyleUnit_Auto == mStylePosition->mOffset.GetLeftUnit()) &&
  1358        (eStyleUnit_Auto == mStylePosition->mOffset.GetRightUnit())) ||
  1359       ((eStyleUnit_Auto == mStylePosition->mOffset.GetTopUnit()) &&
  1360        (eStyleUnit_Auto == mStylePosition->mOffset.GetBottomUnit()))) {
  1361     // Find the nearest containing block frame to the placeholder frame,
  1362     // and return its left edge and width.
  1363     nscoord cbLeftEdge, cbWidth;
  1364     nsIFrame* cbFrame = GetHypotheticalBoxContainer(placeholderFrame,
  1365                                                     cbLeftEdge,
  1366                                                     cbWidth);
  1368     CalculateHypotheticalBox(aPresContext, placeholderFrame, cbFrame,
  1369                              cbLeftEdge, cbWidth, cbrs, hypotheticalBox, aFrameType);
  1372   // Initialize the 'left' and 'right' computed offsets
  1373   // XXX Handle new 'static-position' value...
  1374   bool          leftIsAuto = false, rightIsAuto = false;
  1375   if (eStyleUnit_Auto == mStylePosition->mOffset.GetLeftUnit()) {
  1376     ComputedPhysicalOffsets().left = 0;
  1377     leftIsAuto = true;
  1378   } else {
  1379     ComputedPhysicalOffsets().left = nsLayoutUtils::
  1380       ComputeCBDependentValue(containingBlockWidth,
  1381                               mStylePosition->mOffset.GetLeft());
  1383   if (eStyleUnit_Auto == mStylePosition->mOffset.GetRightUnit()) {
  1384     ComputedPhysicalOffsets().right = 0;
  1385     rightIsAuto = true;
  1386   } else {
  1387     ComputedPhysicalOffsets().right = nsLayoutUtils::
  1388       ComputeCBDependentValue(containingBlockWidth,
  1389                               mStylePosition->mOffset.GetRight());
  1392   // Use the horizontal component of the hypothetical box in the cases
  1393   // where it's needed.
  1394   if (leftIsAuto && rightIsAuto) {
  1395     // Use the direction of the original ("static-position") containing block
  1396     // to dictate whether 'left' or 'right' is treated like 'static-position'.
  1397     if (NS_STYLE_DIRECTION_LTR == placeholderFrame->GetContainingBlock()
  1398                                     ->StyleVisibility()->mDirection) {
  1399       NS_ASSERTION(hypotheticalBox.mLeftIsExact, "should always have "
  1400                    "exact value on containing block's start side");
  1401       ComputedPhysicalOffsets().left = hypotheticalBox.mLeft;
  1402       leftIsAuto = false;
  1403     } else {
  1404       NS_ASSERTION(hypotheticalBox.mRightIsExact, "should always have "
  1405                    "exact value on containing block's start side");
  1406       ComputedPhysicalOffsets().right = containingBlockWidth - hypotheticalBox.mRight;
  1407       rightIsAuto = false;
  1411   // Initialize the 'top' and 'bottom' computed offsets
  1412   bool        topIsAuto = false, bottomIsAuto = false;
  1413   if (eStyleUnit_Auto == mStylePosition->mOffset.GetTopUnit()) {
  1414     ComputedPhysicalOffsets().top = 0;
  1415     topIsAuto = true;
  1416   } else {
  1417     ComputedPhysicalOffsets().top = nsLayoutUtils::
  1418       ComputeHeightDependentValue(containingBlockHeight,
  1419                                   mStylePosition->mOffset.GetTop());
  1421   if (eStyleUnit_Auto == mStylePosition->mOffset.GetBottomUnit()) {
  1422     ComputedPhysicalOffsets().bottom = 0;        
  1423     bottomIsAuto = true;
  1424   } else {
  1425     ComputedPhysicalOffsets().bottom = nsLayoutUtils::
  1426       ComputeHeightDependentValue(containingBlockHeight,
  1427                                   mStylePosition->mOffset.GetBottom());
  1430   if (topIsAuto && bottomIsAuto) {
  1431     // Treat 'top' like 'static-position'
  1432     ComputedPhysicalOffsets().top = hypotheticalBox.mTop;
  1433     topIsAuto = false;
  1436   bool widthIsAuto = eStyleUnit_Auto == mStylePosition->mWidth.GetUnit();
  1437   bool heightIsAuto = eStyleUnit_Auto == mStylePosition->mHeight.GetUnit();
  1439   uint32_t computeSizeFlags = 0;
  1440   if (leftIsAuto || rightIsAuto) {
  1441     computeSizeFlags |= nsIFrame::eShrinkWrap;
  1445     AutoMaybeDisableFontInflation an(frame);
  1447     nsSize size =
  1448       frame->ComputeSize(rendContext,
  1449                          nsSize(containingBlockWidth,
  1450                                 containingBlockHeight),
  1451                          containingBlockWidth, // XXX or mAvailableWidth?
  1452                          nsSize(ComputedPhysicalMargin().LeftRight() +
  1453                                   ComputedPhysicalOffsets().LeftRight(),
  1454                                 ComputedPhysicalMargin().TopBottom() +
  1455                                   ComputedPhysicalOffsets().TopBottom()),
  1456                          nsSize(ComputedPhysicalBorderPadding().LeftRight() -
  1457                                   ComputedPhysicalPadding().LeftRight(),
  1458                                 ComputedPhysicalBorderPadding().TopBottom() -
  1459                                   ComputedPhysicalPadding().TopBottom()),
  1460                          nsSize(ComputedPhysicalPadding().LeftRight(),
  1461                                 ComputedPhysicalPadding().TopBottom()),
  1462                          computeSizeFlags);
  1463     ComputedWidth() = size.width;
  1464     ComputedHeight() = size.height;
  1466   NS_ASSERTION(ComputedWidth() >= 0, "Bogus width");
  1467   NS_ASSERTION(ComputedHeight() == NS_UNCONSTRAINEDSIZE ||
  1468                ComputedHeight() >= 0, "Bogus height");
  1470   // XXX Now that we have ComputeSize, can we condense many of the
  1471   // branches off of widthIsAuto?
  1473   if (leftIsAuto) {
  1474     // We know 'right' is not 'auto' anymore thanks to the hypothetical
  1475     // box code above.
  1476     // Solve for 'left'.
  1477     if (widthIsAuto) {
  1478       // XXXldb This, and the corresponding code in
  1479       // nsAbsoluteContainingBlock.cpp, could probably go away now that
  1480       // we always compute widths.
  1481       ComputedPhysicalOffsets().left = NS_AUTOOFFSET;
  1482     } else {
  1483       ComputedPhysicalOffsets().left = containingBlockWidth - ComputedPhysicalMargin().left -
  1484         ComputedPhysicalBorderPadding().left - ComputedWidth() - ComputedPhysicalBorderPadding().right - 
  1485         ComputedPhysicalMargin().right - ComputedPhysicalOffsets().right;
  1488   } else if (rightIsAuto) {
  1489     // We know 'left' is not 'auto' anymore thanks to the hypothetical
  1490     // box code above.
  1491     // Solve for 'right'.
  1492     if (widthIsAuto) {
  1493       // XXXldb This, and the corresponding code in
  1494       // nsAbsoluteContainingBlock.cpp, could probably go away now that
  1495       // we always compute widths.
  1496       ComputedPhysicalOffsets().right = NS_AUTOOFFSET;
  1497     } else {
  1498       ComputedPhysicalOffsets().right = containingBlockWidth - ComputedPhysicalOffsets().left -
  1499         ComputedPhysicalMargin().left - ComputedPhysicalBorderPadding().left - ComputedWidth() -
  1500         ComputedPhysicalBorderPadding().right - ComputedPhysicalMargin().right;
  1502   } else {
  1503     // Neither 'left' nor 'right' is 'auto'.  However, the width might
  1504     // still not fill all the available space (even though we didn't
  1505     // shrink-wrap) in case:
  1506     //  * width was specified
  1507     //  * we're dealing with a replaced element
  1508     //  * width was constrained by min-width or max-width.
  1510     nscoord availMarginSpace = containingBlockWidth -
  1511                                ComputedPhysicalOffsets().LeftRight() -
  1512                                ComputedPhysicalMargin().LeftRight() -
  1513                                ComputedPhysicalBorderPadding().LeftRight() -
  1514                                ComputedWidth();
  1515     bool marginLeftIsAuto =
  1516       eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit();
  1517     bool marginRightIsAuto =
  1518       eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit();
  1520     if (marginLeftIsAuto) {
  1521       if (marginRightIsAuto) {
  1522         if (availMarginSpace < 0) {
  1523           // Note that this case is different from the neither-'auto'
  1524           // case below, where the spec says to ignore 'left'/'right'.
  1525           if (cbrs &&
  1526               NS_STYLE_DIRECTION_RTL == cbrs->mStyleVisibility->mDirection) {
  1527             // Ignore the specified value for 'margin-left'.
  1528             ComputedPhysicalMargin().left = availMarginSpace;
  1529           } else {
  1530             // Ignore the specified value for 'margin-right'.
  1531             ComputedPhysicalMargin().right = availMarginSpace;
  1533         } else {
  1534           // Both 'margin-left' and 'margin-right' are 'auto', so they get
  1535           // equal values
  1536           ComputedPhysicalMargin().left = availMarginSpace / 2;
  1537           ComputedPhysicalMargin().right = availMarginSpace - ComputedPhysicalMargin().left;
  1539       } else {
  1540         // Just 'margin-left' is 'auto'
  1541         ComputedPhysicalMargin().left = availMarginSpace;
  1543     } else {
  1544       if (marginRightIsAuto) {
  1545         // Just 'margin-right' is 'auto'
  1546         ComputedPhysicalMargin().right = availMarginSpace;
  1547       } else {
  1548         // We're over-constrained so use the direction of the containing
  1549         // block to dictate which value to ignore.  (And note that the
  1550         // spec says to ignore 'left' or 'right' rather than
  1551         // 'margin-left' or 'margin-right'.)
  1552         // Note that this case is different from the both-'auto' case
  1553         // above, where the spec says to ignore
  1554         // 'margin-left'/'margin-right'.
  1555         if (cbrs &&
  1556             NS_STYLE_DIRECTION_RTL == cbrs->mStyleVisibility->mDirection) {
  1557           // Ignore the specified value for 'left'.
  1558           ComputedPhysicalOffsets().left += availMarginSpace;
  1559         } else {
  1560           // Ignore the specified value for 'right'.
  1561           ComputedPhysicalOffsets().right += availMarginSpace;
  1567   if (topIsAuto) {
  1568     // solve for 'top'
  1569     if (heightIsAuto) {
  1570       ComputedPhysicalOffsets().top = NS_AUTOOFFSET;
  1571     } else {
  1572       ComputedPhysicalOffsets().top = containingBlockHeight - ComputedPhysicalMargin().top -
  1573         ComputedPhysicalBorderPadding().top - ComputedHeight() - ComputedPhysicalBorderPadding().bottom - 
  1574         ComputedPhysicalMargin().bottom - ComputedPhysicalOffsets().bottom;
  1576   } else if (bottomIsAuto) {
  1577     // solve for 'bottom'
  1578     if (heightIsAuto) {
  1579       ComputedPhysicalOffsets().bottom = NS_AUTOOFFSET;
  1580     } else {
  1581       ComputedPhysicalOffsets().bottom = containingBlockHeight - ComputedPhysicalOffsets().top -
  1582         ComputedPhysicalMargin().top - ComputedPhysicalBorderPadding().top - ComputedHeight() -
  1583         ComputedPhysicalBorderPadding().bottom - ComputedPhysicalMargin().bottom;
  1585   } else {
  1586     // Neither 'top' nor 'bottom' is 'auto'.
  1587     nscoord autoHeight = containingBlockHeight -
  1588                          ComputedPhysicalOffsets().TopBottom() -
  1589                          ComputedPhysicalMargin().TopBottom() -
  1590                          ComputedPhysicalBorderPadding().TopBottom();
  1591     if (autoHeight < 0) {
  1592       autoHeight = 0;
  1595     if (ComputedHeight() == NS_UNCONSTRAINEDSIZE) {
  1596       // For non-replaced elements with 'height' auto, the 'height'
  1597       // fills the remaining space.
  1598       ComputedHeight() = autoHeight;
  1600       // XXX Do these need box-sizing adjustments?
  1601       if (ComputedHeight() > ComputedMaxHeight())
  1602         ComputedHeight() = ComputedMaxHeight();
  1603       if (ComputedHeight() < ComputedMinHeight())
  1604         ComputedHeight() = ComputedMinHeight();
  1607     // The height might still not fill all the available space in case:
  1608     //  * height was specified
  1609     //  * we're dealing with a replaced element
  1610     //  * height was constrained by min-height or max-height.
  1611     nscoord availMarginSpace = autoHeight - ComputedHeight();
  1612     bool marginTopIsAuto =
  1613       eStyleUnit_Auto == mStyleMargin->mMargin.GetTopUnit();
  1614     bool marginBottomIsAuto =
  1615       eStyleUnit_Auto == mStyleMargin->mMargin.GetBottomUnit();
  1617     if (marginTopIsAuto) {
  1618       if (marginBottomIsAuto) {
  1619         if (availMarginSpace < 0) {
  1620           // FIXME: Note that the spec doesn't actually say we should do this!
  1621           ComputedPhysicalMargin().bottom = availMarginSpace;
  1622         } else {
  1623           // Both 'margin-top' and 'margin-bottom' are 'auto', so they get
  1624           // equal values
  1625           ComputedPhysicalMargin().top = availMarginSpace / 2;
  1626           ComputedPhysicalMargin().bottom = availMarginSpace - ComputedPhysicalMargin().top;
  1628       } else {
  1629         // Just 'margin-top' is 'auto'
  1630         ComputedPhysicalMargin().top = availMarginSpace;
  1632     } else {
  1633       if (marginBottomIsAuto) {
  1634         // Just 'margin-bottom' is 'auto'
  1635         ComputedPhysicalMargin().bottom = availMarginSpace;
  1636       } else {
  1637         // We're over-constrained so ignore the specified value for
  1638         // 'bottom'.  (And note that the spec says to ignore 'bottom'
  1639         // rather than 'margin-bottom'.)
  1640         ComputedPhysicalOffsets().bottom += availMarginSpace;
  1646 nscoord 
  1647 GetVerticalMarginBorderPadding(const nsHTMLReflowState* aReflowState)
  1649   nscoord result = 0;
  1650   if (!aReflowState) return result;
  1652   // zero auto margins
  1653   nsMargin margin = aReflowState->ComputedPhysicalMargin();
  1654   if (NS_AUTOMARGIN == margin.top) 
  1655     margin.top = 0;
  1656   if (NS_AUTOMARGIN == margin.bottom) 
  1657     margin.bottom = 0;
  1659   result += margin.top + margin.bottom;
  1660   result += aReflowState->ComputedPhysicalBorderPadding().top + 
  1661             aReflowState->ComputedPhysicalBorderPadding().bottom;
  1663   return result;
  1666 /* Get the height based on the viewport of the containing block specified 
  1667  * in aReflowState when the containing block has mComputedHeight == NS_AUTOHEIGHT
  1668  * This will walk up the chain of containing blocks looking for a computed height
  1669  * until it finds the canvas frame, or it encounters a frame that is not a block,
  1670  * area, or scroll frame. This handles compatibility with IE (see bug 85016 and bug 219693)
  1672  *  When we encounter scrolledContent block frames, we skip over them, since they are guaranteed to not be useful for computing the containing block.
  1674  * See also IsQuirkContainingBlockHeight.
  1675  */
  1676 static nscoord
  1677 CalcQuirkContainingBlockHeight(const nsHTMLReflowState* aCBReflowState)
  1679   const nsHTMLReflowState* firstAncestorRS = nullptr; // a candidate for html frame
  1680   const nsHTMLReflowState* secondAncestorRS = nullptr; // a candidate for body frame
  1682   // initialize the default to NS_AUTOHEIGHT as this is the containings block
  1683   // computed height when this function is called. It is possible that we 
  1684   // don't alter this height especially if we are restricted to one level
  1685   nscoord result = NS_AUTOHEIGHT; 
  1687   const nsHTMLReflowState* rs = aCBReflowState;
  1688   for (; rs; rs = rs->parentReflowState) {
  1689     nsIAtom* frameType = rs->frame->GetType();
  1690     // if the ancestor is auto height then skip it and continue up if it 
  1691     // is the first block frame and possibly the body/html
  1692     if (nsGkAtoms::blockFrame == frameType ||
  1693 #ifdef MOZ_XUL
  1694         nsGkAtoms::XULLabelFrame == frameType ||
  1695 #endif
  1696         nsGkAtoms::scrollFrame == frameType) {
  1698       secondAncestorRS = firstAncestorRS;
  1699       firstAncestorRS = rs;
  1701       // If the current frame we're looking at is positioned, we don't want to
  1702       // go any further (see bug 221784).  The behavior we want here is: 1) If
  1703       // not auto-height, use this as the percentage base.  2) If auto-height,
  1704       // keep looking, unless the frame is positioned.
  1705       if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
  1706         if (rs->frame->IsAbsolutelyPositioned()) {
  1707           break;
  1708         } else {
  1709           continue;
  1713     else if (nsGkAtoms::canvasFrame == frameType) {
  1714       // Always continue on to the height calculation
  1716     else if (nsGkAtoms::pageContentFrame == frameType) {
  1717       nsIFrame* prevInFlow = rs->frame->GetPrevInFlow();
  1718       // only use the page content frame for a height basis if it is the first in flow
  1719       if (prevInFlow) 
  1720         break;
  1722     else {
  1723       break;
  1726     // if the ancestor is the page content frame then the percent base is 
  1727     // the avail height, otherwise it is the computed height
  1728     result = (nsGkAtoms::pageContentFrame == frameType)
  1729              ? rs->AvailableHeight() : rs->ComputedHeight();
  1730     // if unconstrained - don't sutract borders - would result in huge height
  1731     if (NS_AUTOHEIGHT == result) return result;
  1733     // if we got to the canvas or page content frame, then subtract out 
  1734     // margin/border/padding for the BODY and HTML elements
  1735     if ((nsGkAtoms::canvasFrame == frameType) || 
  1736         (nsGkAtoms::pageContentFrame == frameType)) {
  1738       result -= GetVerticalMarginBorderPadding(firstAncestorRS); 
  1739       result -= GetVerticalMarginBorderPadding(secondAncestorRS); 
  1741 #ifdef DEBUG
  1742       // make sure the first ancestor is the HTML and the second is the BODY
  1743       if (firstAncestorRS) {
  1744         nsIContent* frameContent = firstAncestorRS->frame->GetContent();
  1745         if (frameContent) {
  1746           nsIAtom *contentTag = frameContent->Tag();
  1747           NS_ASSERTION(contentTag == nsGkAtoms::html, "First ancestor is not HTML");
  1750       if (secondAncestorRS) {
  1751         nsIContent* frameContent = secondAncestorRS->frame->GetContent();
  1752         if (frameContent) {
  1753           nsIAtom *contentTag = frameContent->Tag();
  1754           NS_ASSERTION(contentTag == nsGkAtoms::body, "Second ancestor is not BODY");
  1757 #endif
  1760     // if we got to the html frame (a block child of the canvas) ...
  1761     else if (nsGkAtoms::blockFrame == frameType &&
  1762              rs->parentReflowState &&
  1763              nsGkAtoms::canvasFrame ==
  1764                rs->parentReflowState->frame->GetType()) {
  1765       // ... then subtract out margin/border/padding for the BODY element
  1766       result -= GetVerticalMarginBorderPadding(secondAncestorRS);
  1768     break;
  1771   // Make sure not to return a negative height here!
  1772   return std::max(result, 0);
  1775 // Called by InitConstraints() to compute the containing block rectangle for
  1776 // the element. Handles the special logic for absolutely positioned elements
  1777 void
  1778 nsHTMLReflowState::ComputeContainingBlockRectangle(nsPresContext*          aPresContext,
  1779                                                    const nsHTMLReflowState* aContainingBlockRS,
  1780                                                    nscoord&                 aContainingBlockWidth,
  1781                                                    nscoord&                 aContainingBlockHeight)
  1783   // Unless the element is absolutely positioned, the containing block is
  1784   // formed by the content edge of the nearest block-level ancestor
  1785   aContainingBlockWidth = aContainingBlockRS->ComputedWidth();
  1786   aContainingBlockHeight = aContainingBlockRS->ComputedHeight();
  1788   // mFrameType for abs-pos tables is NS_CSS_FRAME_TYPE_BLOCK, so we need to
  1789   // special case them here.
  1790   if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE ||
  1791       (frame->GetType() == nsGkAtoms::tableFrame &&
  1792        frame->IsAbsolutelyPositioned() &&
  1793        (frame->GetParent()->GetStateBits() & NS_FRAME_OUT_OF_FLOW))) {
  1794     // See if the ancestor is block-level or inline-level
  1795     if (NS_FRAME_GET_TYPE(aContainingBlockRS->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) {
  1796       // Base our size on the actual size of the frame.  In cases when this is
  1797       // completely bogus (eg initial reflow), this code shouldn't even be
  1798       // called, since the code in nsInlineFrame::Reflow will pass in
  1799       // the containing block dimensions to our constructor.
  1800       // XXXbz we should be taking the in-flows into account too, but
  1801       // that's very hard.
  1802       nsMargin computedBorder = aContainingBlockRS->ComputedPhysicalBorderPadding() -
  1803         aContainingBlockRS->ComputedPhysicalPadding();
  1804       aContainingBlockWidth = aContainingBlockRS->frame->GetRect().width -
  1805         computedBorder.LeftRight();
  1806       NS_ASSERTION(aContainingBlockWidth >= 0,
  1807                    "Negative containing block width!");
  1808       aContainingBlockHeight = aContainingBlockRS->frame->GetRect().height -
  1809         computedBorder.TopBottom();
  1810       NS_ASSERTION(aContainingBlockHeight >= 0,
  1811                    "Negative containing block height!");
  1812     } else {
  1813       // If the ancestor is block-level, the containing block is formed by the
  1814       // padding edge of the ancestor
  1815       aContainingBlockWidth += aContainingBlockRS->ComputedPhysicalPadding().LeftRight();
  1816       aContainingBlockHeight += aContainingBlockRS->ComputedPhysicalPadding().TopBottom();
  1818   } else {
  1819     // an element in quirks mode gets a containing block based on looking for a
  1820     // parent with a non-auto height if the element has a percent height
  1821     // Note: We don't emulate this quirk for percents in calc().
  1822     if (NS_AUTOHEIGHT == aContainingBlockHeight) {
  1823       if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
  1824           mStylePosition->mHeight.GetUnit() == eStyleUnit_Percent) {
  1825         aContainingBlockHeight = CalcQuirkContainingBlockHeight(aContainingBlockRS);
  1831 static eNormalLineHeightControl GetNormalLineHeightCalcControl(void)
  1833   if (sNormalLineHeightControl == eUninitialized) {
  1834     // browser.display.normal_lineheight_calc_control is not user
  1835     // changeable, so no need to register callback for it.
  1836     int32_t val =
  1837       Preferences::GetInt("browser.display.normal_lineheight_calc_control",
  1838                           eNoExternalLeading);
  1839     sNormalLineHeightControl = static_cast<eNormalLineHeightControl>(val);
  1841   return sNormalLineHeightControl;
  1844 static inline bool
  1845 IsSideCaption(nsIFrame* aFrame, const nsStyleDisplay* aStyleDisplay)
  1847   if (aStyleDisplay->mDisplay != NS_STYLE_DISPLAY_TABLE_CAPTION)
  1848     return false;
  1849   uint8_t captionSide = aFrame->StyleTableBorder()->mCaptionSide;
  1850   return captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
  1851          captionSide == NS_STYLE_CAPTION_SIDE_RIGHT;
  1854 static nsFlexContainerFrame*
  1855 GetFlexContainer(nsIFrame* aFrame)
  1857   nsIFrame* parent = aFrame->GetParent();
  1858   if (!parent ||
  1859       parent->GetType() != nsGkAtoms::flexContainerFrame) {
  1860     return nullptr;
  1863   return static_cast<nsFlexContainerFrame*>(parent);
  1866 // Flex items resolve percentage margin & padding against the flex
  1867 // container's height (which is the containing block height).
  1868 // For everything else: the CSS21 spec requires that margin and padding
  1869 // percentage values are calculated with respect to the *width* of the
  1870 // containing block, even for margin & padding in the vertical axis.
  1871 static nscoord
  1872 VerticalOffsetPercentBasis(const nsIFrame* aFrame,
  1873                            nscoord aContainingBlockWidth,
  1874                            nscoord aContainingBlockHeight)
  1876   if (!aFrame->IsFlexItem()) {
  1877     return aContainingBlockWidth;
  1880   if (aContainingBlockHeight == NS_AUTOHEIGHT) {
  1881     return 0;
  1884   return aContainingBlockHeight;
  1887 // XXX refactor this code to have methods for each set of properties
  1888 // we are computing: width,height,line-height; margin; offsets
  1890 void
  1891 nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext,
  1892                                    nscoord         aContainingBlockWidth,
  1893                                    nscoord         aContainingBlockHeight,
  1894                                    const nsMargin* aBorder,
  1895                                    const nsMargin* aPadding,
  1896                                    nsIAtom* aFrameType)
  1898   DISPLAY_INIT_CONSTRAINTS(frame, this,
  1899                            aContainingBlockWidth, aContainingBlockHeight,
  1900                            aBorder, aPadding);
  1902   // If this is a reflow root, then set the computed width and
  1903   // height equal to the available space
  1904   if (nullptr == parentReflowState || mFlags.mDummyParentReflowState) {
  1905     // XXXldb This doesn't mean what it used to!
  1906     InitOffsets(aContainingBlockWidth,
  1907                 VerticalOffsetPercentBasis(frame, aContainingBlockWidth,
  1908                                            aContainingBlockHeight),
  1909                 aFrameType, aBorder, aPadding);
  1910     // Override mComputedMargin since reflow roots start from the
  1911     // frame's boundary, which is inside the margin.
  1912     ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
  1913     ComputedPhysicalOffsets().SizeTo(0, 0, 0, 0);
  1915     ComputedWidth() = AvailableWidth() - ComputedPhysicalBorderPadding().LeftRight();
  1916     if (ComputedWidth() < 0)
  1917       ComputedWidth() = 0;
  1918     if (AvailableHeight() != NS_UNCONSTRAINEDSIZE) {
  1919       ComputedHeight() = AvailableHeight() - ComputedPhysicalBorderPadding().TopBottom();
  1920       if (ComputedHeight() < 0)
  1921         ComputedHeight() = 0;
  1922     } else {
  1923       ComputedHeight() = NS_UNCONSTRAINEDSIZE;
  1926     ComputedMinWidth() = ComputedMinHeight() = 0;
  1927     ComputedMaxWidth() = ComputedMaxHeight() = NS_UNCONSTRAINEDSIZE;
  1928   } else {
  1929     // Get the containing block reflow state
  1930     const nsHTMLReflowState* cbrs = mCBReflowState;
  1931     NS_ASSERTION(nullptr != cbrs, "no containing block");
  1933     // If we weren't given a containing block width and height, then
  1934     // compute one
  1935     if (aContainingBlockWidth == -1) {
  1936       ComputeContainingBlockRectangle(aPresContext, cbrs, aContainingBlockWidth, 
  1937                                       aContainingBlockHeight);
  1940     // See if the containing block height is based on the size of its
  1941     // content
  1942     nsIAtom* fType;
  1943     if (NS_AUTOHEIGHT == aContainingBlockHeight) {
  1944       // See if the containing block is a cell frame which needs
  1945       // to use the mComputedHeight of the cell instead of what the cell block passed in.
  1946       // XXX It seems like this could lead to bugs with min-height and friends
  1947       if (cbrs->parentReflowState) {
  1948         fType = cbrs->frame->GetType();
  1949         if (IS_TABLE_CELL(fType)) {
  1950           // use the cell's computed height 
  1951           aContainingBlockHeight = cbrs->ComputedHeight();
  1956     // XXX Might need to also pass the CB height (not width) for page boxes,
  1957     // too, if we implement them.
  1958     InitOffsets(aContainingBlockWidth,
  1959                 VerticalOffsetPercentBasis(frame, aContainingBlockWidth,
  1960                                            aContainingBlockHeight),
  1961                 aFrameType, aBorder, aPadding);
  1963     const nsStyleCoord &height = mStylePosition->mHeight;
  1964     nsStyleUnit heightUnit = height.GetUnit();
  1966     // Check for a percentage based height and a containing block height
  1967     // that depends on the content height
  1968     // XXX twiddling heightUnit doesn't help anymore
  1969     // FIXME Shouldn't we fix that?
  1970     if (height.HasPercent()) {
  1971       if (NS_AUTOHEIGHT == aContainingBlockHeight) {
  1972         // this if clause enables %-height on replaced inline frames,
  1973         // such as images.  See bug 54119.  The else clause "heightUnit = eStyleUnit_Auto;"
  1974         // used to be called exclusively.
  1975         if (NS_FRAME_REPLACED(NS_CSS_FRAME_TYPE_INLINE) == mFrameType ||
  1976             NS_FRAME_REPLACED_CONTAINS_BLOCK(
  1977                 NS_CSS_FRAME_TYPE_INLINE) == mFrameType) {
  1978           // Get the containing block reflow state
  1979           NS_ASSERTION(nullptr != cbrs, "no containing block");
  1980           // in quirks mode, get the cb height using the special quirk method
  1981           if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode()) {
  1982             if (!IS_TABLE_CELL(fType)) {
  1983               aContainingBlockHeight = CalcQuirkContainingBlockHeight(cbrs);
  1984               if (aContainingBlockHeight == NS_AUTOHEIGHT) {
  1985                 heightUnit = eStyleUnit_Auto;
  1988             else {
  1989               heightUnit = eStyleUnit_Auto;
  1992           // in standard mode, use the cb height.  if it's "auto", as will be the case
  1993           // by default in BODY, use auto height as per CSS2 spec.
  1994           else 
  1996             if (NS_AUTOHEIGHT != cbrs->ComputedHeight())
  1997               aContainingBlockHeight = cbrs->ComputedHeight();
  1998             else
  1999               heightUnit = eStyleUnit_Auto;
  2002         else {
  2003           // default to interpreting the height like 'auto'
  2004           heightUnit = eStyleUnit_Auto;
  2009     // Compute our offsets if the element is relatively positioned.  We need
  2010     // the correct containing block width and height here, which is why we need
  2011     // to do it after all the quirks-n-such above. (If the element is sticky
  2012     // positioned, we need to wait until the scroll container knows its size,
  2013     // so we compute offsets from StickyScrollContainer::UpdatePositions.)
  2014     if (mStyleDisplay->IsRelativelyPositioned(frame) &&
  2015         NS_STYLE_POSITION_RELATIVE == mStyleDisplay->mPosition) {
  2016       uint8_t direction = NS_STYLE_DIRECTION_LTR;
  2017       if (cbrs && NS_STYLE_DIRECTION_RTL == cbrs->mStyleVisibility->mDirection) {
  2018         direction = NS_STYLE_DIRECTION_RTL;
  2020       ComputeRelativeOffsets(direction, frame, aContainingBlockWidth,
  2021           aContainingBlockHeight, ComputedPhysicalOffsets());
  2022     } else {
  2023       // Initialize offsets to 0
  2024       ComputedPhysicalOffsets().SizeTo(0, 0, 0, 0);
  2027     // Calculate the computed values for min and max properties.  Note that
  2028     // this MUST come after we've computed our border and padding.
  2029     ComputeMinMaxValues(aContainingBlockWidth, aContainingBlockHeight, cbrs);
  2031     // Calculate the computed width and height. This varies by frame type
  2033     if (NS_CSS_FRAME_TYPE_INTERNAL_TABLE == mFrameType) {
  2034       // Internal table elements. The rules vary depending on the type.
  2035       // Calculate the computed width
  2036       bool rowOrRowGroup = false;
  2037       const nsStyleCoord &width = mStylePosition->mWidth;
  2038       nsStyleUnit widthUnit = width.GetUnit();
  2039       if ((NS_STYLE_DISPLAY_TABLE_ROW == mStyleDisplay->mDisplay) ||
  2040           (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == mStyleDisplay->mDisplay)) {
  2041         // 'width' property doesn't apply to table rows and row groups
  2042         widthUnit = eStyleUnit_Auto;
  2043         rowOrRowGroup = true;
  2046       // calc() with percentages acts like auto on internal table elements
  2047       if (eStyleUnit_Auto == widthUnit ||
  2048           (width.IsCalcUnit() && width.CalcHasPercent())) {
  2049         ComputedWidth() = AvailableWidth();
  2051         if ((ComputedWidth() != NS_UNCONSTRAINEDSIZE) && !rowOrRowGroup){
  2052           // Internal table elements don't have margins. Only tables and
  2053           // cells have border and padding
  2054           ComputedWidth() -= ComputedPhysicalBorderPadding().left +
  2055             ComputedPhysicalBorderPadding().right;
  2056           if (ComputedWidth() < 0)
  2057             ComputedWidth() = 0;
  2059         NS_ASSERTION(ComputedWidth() >= 0, "Bogus computed width");
  2061       } else {
  2062         NS_ASSERTION(widthUnit == mStylePosition->mWidth.GetUnit(),
  2063                      "unexpected width unit change");
  2064         ComputedWidth() = ComputeWidthValue(aContainingBlockWidth,
  2065                                            mStylePosition->mBoxSizing,
  2066                                            mStylePosition->mWidth);
  2069       // Calculate the computed height
  2070       if ((NS_STYLE_DISPLAY_TABLE_COLUMN == mStyleDisplay->mDisplay) ||
  2071           (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == mStyleDisplay->mDisplay)) {
  2072         // 'height' property doesn't apply to table columns and column groups
  2073         heightUnit = eStyleUnit_Auto;
  2075       // calc() with percentages acts like 'auto' on internal table elements
  2076       if (eStyleUnit_Auto == heightUnit ||
  2077           (height.IsCalcUnit() && height.CalcHasPercent())) {
  2078         ComputedHeight() = NS_AUTOHEIGHT;
  2079       } else {
  2080         NS_ASSERTION(heightUnit == mStylePosition->mHeight.GetUnit(),
  2081                      "unexpected height unit change");
  2082         ComputedHeight() = ComputeHeightValue(aContainingBlockHeight, 
  2083                                              mStylePosition->mBoxSizing,
  2084                                              mStylePosition->mHeight);
  2087       // Doesn't apply to table elements
  2088       ComputedMinWidth() = ComputedMinHeight() = 0;
  2089       ComputedMaxWidth() = ComputedMaxHeight() = NS_UNCONSTRAINEDSIZE;
  2091     } else if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE) {
  2092       // XXX not sure if this belongs here or somewhere else - cwk
  2093       InitAbsoluteConstraints(aPresContext, cbrs, aContainingBlockWidth,
  2094                               aContainingBlockHeight, aFrameType);
  2095     } else {
  2096       AutoMaybeDisableFontInflation an(frame);
  2098       bool isBlock = NS_CSS_FRAME_TYPE_BLOCK == NS_FRAME_GET_TYPE(mFrameType);
  2099       uint32_t computeSizeFlags = isBlock ? 0 : nsIFrame::eShrinkWrap;
  2101       // Make sure legend frames with display:block and width:auto still
  2102       // shrink-wrap.
  2103       if (isBlock &&
  2104           ((aFrameType == nsGkAtoms::legendFrame &&
  2105             frame->StyleContext()->GetPseudo() != nsCSSAnonBoxes::scrolledContent) ||
  2106            (aFrameType == nsGkAtoms::scrollFrame &&
  2107             frame->GetContentInsertionFrame()->GetType() == nsGkAtoms::legendFrame))) {
  2108         computeSizeFlags |= nsIFrame::eShrinkWrap;
  2111       const nsFlexContainerFrame* flexContainerFrame = GetFlexContainer(frame);
  2112       if (flexContainerFrame) {
  2113         computeSizeFlags |= nsIFrame::eShrinkWrap;
  2115         // If we're inside of a flex container that needs to measure our
  2116         // auto height, pass that information along to ComputeSize().
  2117         if (mFlags.mIsFlexContainerMeasuringHeight) {
  2118           computeSizeFlags |= nsIFrame::eUseAutoHeight;
  2120       } else {
  2121         MOZ_ASSERT(!mFlags.mIsFlexContainerMeasuringHeight,
  2122                    "We're not in a flex container, so the flag "
  2123                    "'mIsFlexContainerMeasuringHeight' shouldn't be set");
  2126       nsSize size =
  2127         frame->ComputeSize(rendContext,
  2128                            nsSize(aContainingBlockWidth,
  2129                                   aContainingBlockHeight),
  2130                            AvailableWidth(),
  2131                            nsSize(ComputedPhysicalMargin().LeftRight(),
  2132                                   ComputedPhysicalMargin().TopBottom()),
  2133                            nsSize(ComputedPhysicalBorderPadding().LeftRight() -
  2134                                     ComputedPhysicalPadding().LeftRight(),
  2135                                   ComputedPhysicalBorderPadding().TopBottom() -
  2136                                     ComputedPhysicalPadding().TopBottom()),
  2137                            nsSize(ComputedPhysicalPadding().LeftRight(),
  2138                                   ComputedPhysicalPadding().TopBottom()),
  2139                            computeSizeFlags);
  2141       ComputedWidth() = size.width;
  2142       ComputedHeight() = size.height;
  2143       NS_ASSERTION(ComputedWidth() >= 0, "Bogus width");
  2144       NS_ASSERTION(ComputedHeight() == NS_UNCONSTRAINEDSIZE ||
  2145                    ComputedHeight() >= 0, "Bogus height");
  2147       // Exclude inline tables and flex items from the block margin calculations
  2148       if (isBlock &&
  2149           !IsSideCaption(frame, mStyleDisplay) &&
  2150           mStyleDisplay->mDisplay != NS_STYLE_DISPLAY_INLINE_TABLE &&
  2151           !flexContainerFrame) {
  2152         CalculateBlockSideMargins(AvailableWidth(), ComputedWidth(), aFrameType);
  2158 static void
  2159 UpdateProp(FrameProperties& aProps,
  2160            const FramePropertyDescriptor* aProperty,
  2161            bool aNeeded,
  2162            nsMargin& aNewValue)
  2164   if (aNeeded) {
  2165     nsMargin* propValue = static_cast<nsMargin*>(aProps.Get(aProperty));
  2166     if (propValue) {
  2167       *propValue = aNewValue;
  2168     } else {
  2169       aProps.Set(aProperty, new nsMargin(aNewValue));
  2171   } else {
  2172     aProps.Delete(aProperty);
  2176 void
  2177 nsCSSOffsetState::InitOffsets(nscoord aHorizontalPercentBasis,
  2178                               nscoord aVerticalPercentBasis,
  2179                               nsIAtom* aFrameType,
  2180                               const nsMargin *aBorder,
  2181                               const nsMargin *aPadding)
  2183   DISPLAY_INIT_OFFSETS(frame, this,
  2184                        aHorizontalPercentBasis,
  2185                        aVerticalPercentBasis,
  2186                        aBorder, aPadding);
  2188   // Since we are in reflow, we don't need to store these properties anymore
  2189   // unless they are dependent on width, in which case we store the new value.
  2190   nsPresContext *presContext = frame->PresContext();
  2191   FrameProperties props(presContext->PropertyTable(), frame);
  2192   props.Delete(nsIFrame::UsedBorderProperty());
  2194   // Compute margins from the specified margin style information. These
  2195   // become the default computed values, and may be adjusted below
  2196   // XXX fix to provide 0,0 for the top&bottom margins for
  2197   // inline-non-replaced elements
  2198   bool needMarginProp = ComputeMargin(aHorizontalPercentBasis,
  2199                                       aVerticalPercentBasis);
  2200   // XXX We need to include 'auto' horizontal margins in this too!
  2201   // ... but if we did that, we'd need to fix nsFrame::GetUsedMargin
  2202   // to use it even when the margins are all zero (since sometimes
  2203   // they get treated as auto)
  2204   ::UpdateProp(props, nsIFrame::UsedMarginProperty(), needMarginProp,
  2205                ComputedPhysicalMargin());
  2208   const nsStyleDisplay *disp = frame->StyleDisplay();
  2209   bool isThemed = frame->IsThemed(disp);
  2210   bool needPaddingProp;
  2211   nsIntMargin widget;
  2212   if (isThemed &&
  2213       presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
  2214                                                 frame, disp->mAppearance,
  2215                                                 &widget)) {
  2216     ComputedPhysicalPadding().top = presContext->DevPixelsToAppUnits(widget.top);
  2217     ComputedPhysicalPadding().right = presContext->DevPixelsToAppUnits(widget.right);
  2218     ComputedPhysicalPadding().bottom = presContext->DevPixelsToAppUnits(widget.bottom);
  2219     ComputedPhysicalPadding().left = presContext->DevPixelsToAppUnits(widget.left);
  2220     needPaddingProp = false;
  2222   else if (frame->IsSVGText()) {
  2223     ComputedPhysicalPadding().SizeTo(0, 0, 0, 0);
  2224     needPaddingProp = false;
  2226   else if (aPadding) { // padding is an input arg
  2227     ComputedPhysicalPadding() = *aPadding;
  2228     needPaddingProp = frame->StylePadding()->IsWidthDependent() ||
  2229 	  (frame->GetStateBits() & NS_FRAME_REFLOW_ROOT);
  2231   else {
  2232     needPaddingProp = ComputePadding(aHorizontalPercentBasis,
  2233                                      aVerticalPercentBasis, aFrameType);
  2236   if (isThemed) {
  2237     nsIntMargin widget;
  2238     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
  2239                                              frame, disp->mAppearance,
  2240                                              &widget);
  2241     ComputedPhysicalBorderPadding().top =
  2242       presContext->DevPixelsToAppUnits(widget.top);
  2243     ComputedPhysicalBorderPadding().right =
  2244       presContext->DevPixelsToAppUnits(widget.right);
  2245     ComputedPhysicalBorderPadding().bottom =
  2246       presContext->DevPixelsToAppUnits(widget.bottom);
  2247     ComputedPhysicalBorderPadding().left =
  2248       presContext->DevPixelsToAppUnits(widget.left);
  2250   else if (frame->IsSVGText()) {
  2251     ComputedPhysicalBorderPadding().SizeTo(0, 0, 0, 0);
  2253   else if (aBorder) {  // border is an input arg
  2254     ComputedPhysicalBorderPadding() = *aBorder;
  2256   else {
  2257     ComputedPhysicalBorderPadding() = frame->StyleBorder()->GetComputedBorder();
  2259   ComputedPhysicalBorderPadding() += ComputedPhysicalPadding();
  2261   if (aFrameType == nsGkAtoms::tableFrame) {
  2262     nsTableFrame *tableFrame = static_cast<nsTableFrame*>(frame);
  2264     if (tableFrame->IsBorderCollapse()) {
  2265       // border-collapsed tables don't use any of their padding, and
  2266       // only part of their border.  We need to do this here before we
  2267       // try to do anything like handling 'auto' widths,
  2268       // 'box-sizing', or 'auto' margins.
  2269       ComputedPhysicalPadding().SizeTo(0,0,0,0);
  2270       ComputedPhysicalBorderPadding() = tableFrame->GetIncludedOuterBCBorder();
  2273     // The margin is inherited to the outer table frame via
  2274     // the ::-moz-table-outer rule in ua.css.
  2275     ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
  2276   } else if (aFrameType == nsGkAtoms::scrollbarFrame) {
  2277     // scrollbars may have had their width or height smashed to zero
  2278     // by the associated scrollframe, in which case we must not report
  2279     // any padding or border.
  2280     nsSize size(frame->GetSize());
  2281     if (size.width == 0 || size.height == 0) {
  2282       ComputedPhysicalPadding().SizeTo(0,0,0,0);
  2283       ComputedPhysicalBorderPadding().SizeTo(0,0,0,0);
  2286   ::UpdateProp(props, nsIFrame::UsedPaddingProperty(), needPaddingProp,
  2287                ComputedPhysicalPadding());
  2290 // This code enforces section 10.3.3 of the CSS2 spec for this formula:
  2291 //
  2292 // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' +
  2293 //   'padding-right' + 'border-right-width' + 'margin-right'
  2294 //   = width of containing block 
  2295 //
  2296 // Note: the width unit is not auto when this is called
  2297 void
  2298 nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailWidth,
  2299                                              nscoord aComputedWidth,
  2300                                              nsIAtom* aFrameType)
  2302   NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aComputedWidth &&
  2303                    NS_UNCONSTRAINEDSIZE != aAvailWidth,
  2304                    "have unconstrained width; this should only result from "
  2305                    "very large sizes, not attempts at intrinsic width "
  2306                    "calculation");
  2308   nscoord sum = ComputedPhysicalMargin().left + ComputedPhysicalBorderPadding().left +
  2309     aComputedWidth + ComputedPhysicalBorderPadding().right + ComputedPhysicalMargin().right;
  2310   if (sum == aAvailWidth)
  2311     // The sum is already correct
  2312     return;
  2314   // Determine the left and right margin values. The width value
  2315   // remains constant while we do this.
  2317   // Calculate how much space is available for margins
  2318   nscoord availMarginSpace = aAvailWidth - sum;
  2320   // If the available margin space is negative, then don't follow the
  2321   // usual overconstraint rules.
  2322   if (availMarginSpace < 0) {
  2323     if (mCBReflowState &&
  2324         mCBReflowState->mStyleVisibility->mDirection == NS_STYLE_DIRECTION_RTL) {
  2325       ComputedPhysicalMargin().left += availMarginSpace;
  2326     } else {
  2327       ComputedPhysicalMargin().right += availMarginSpace;
  2329     return;
  2332   // The css2 spec clearly defines how block elements should behave
  2333   // in section 10.3.3.
  2334   bool isAutoLeftMargin =
  2335     eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit();
  2336   bool isAutoRightMargin =
  2337     eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit();
  2338   if (!isAutoLeftMargin && !isAutoRightMargin) {
  2339     // Neither margin is 'auto' so we're over constrained. Use the
  2340     // 'direction' property of the parent to tell which margin to
  2341     // ignore
  2342     // First check if there is an HTML alignment that we should honor
  2343     const nsHTMLReflowState* prs = parentReflowState;
  2344     if (aFrameType == nsGkAtoms::tableFrame) {
  2345       NS_ASSERTION(prs->frame->GetType() == nsGkAtoms::tableOuterFrame,
  2346                    "table not inside outer table");
  2347       // Center the table within the outer table based on the alignment
  2348       // of the outer table's parent.
  2349       prs = prs->parentReflowState;
  2351     if (prs &&
  2352         (prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_LEFT ||
  2353          prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
  2354          prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)) {
  2355       isAutoLeftMargin =
  2356         prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_LEFT;
  2357       isAutoRightMargin =
  2358         prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_RIGHT;
  2360     // Otherwise apply the CSS rules, and ignore one margin by forcing
  2361     // it to 'auto', depending on 'direction'.
  2362     else if (mCBReflowState &&
  2363              NS_STYLE_DIRECTION_RTL == mCBReflowState->mStyleVisibility->mDirection) {
  2364       isAutoLeftMargin = true;
  2366     else {
  2367       isAutoRightMargin = true;
  2371   // Logic which is common to blocks and tables
  2372   // The computed margins need not be zero because the 'auto' could come from
  2373   // overconstraint or from HTML alignment so values need to be accumulated
  2375   if (isAutoLeftMargin) {
  2376     if (isAutoRightMargin) {
  2377       // Both margins are 'auto' so the computed addition should be equal
  2378       nscoord forLeft = availMarginSpace / 2;
  2379       ComputedPhysicalMargin().left  += forLeft;
  2380       ComputedPhysicalMargin().right += availMarginSpace - forLeft;
  2381     } else {
  2382       ComputedPhysicalMargin().left += availMarginSpace;
  2384   } else if (isAutoRightMargin) {
  2385     ComputedPhysicalMargin().right += availMarginSpace;
  2389 #define NORMAL_LINE_HEIGHT_FACTOR 1.2f    // in term of emHeight 
  2390 // For "normal" we use the font's normal line height (em height + leading).
  2391 // If both internal leading and  external leading specified by font itself
  2392 // are zeros, we should compensate this by creating extra (external) leading 
  2393 // in eCompensateLeading mode. This is necessary because without this 
  2394 // compensation, normal line height might looks too tight. 
  2396 // For risk management, we use preference to control the behavior, and 
  2397 // eNoExternalLeading is the old behavior.
  2398 static nscoord
  2399 GetNormalLineHeight(nsFontMetrics* aFontMetrics)
  2401   NS_PRECONDITION(nullptr != aFontMetrics, "no font metrics");
  2403   nscoord normalLineHeight;
  2405   nscoord externalLeading = aFontMetrics->ExternalLeading();
  2406   nscoord internalLeading = aFontMetrics->InternalLeading();
  2407   nscoord emHeight = aFontMetrics->EmHeight();
  2408   switch (GetNormalLineHeightCalcControl()) {
  2409   case eIncludeExternalLeading:
  2410     normalLineHeight = emHeight+ internalLeading + externalLeading;
  2411     break;
  2412   case eCompensateLeading:
  2413     if (!internalLeading && !externalLeading)
  2414       normalLineHeight = NSToCoordRound(emHeight * NORMAL_LINE_HEIGHT_FACTOR);
  2415     else
  2416       normalLineHeight = emHeight+ internalLeading + externalLeading;
  2417     break;
  2418   default:
  2419     //case eNoExternalLeading:
  2420     normalLineHeight = emHeight + internalLeading;
  2422   return normalLineHeight;
  2425 static inline nscoord
  2426 ComputeLineHeight(nsStyleContext* aStyleContext,
  2427                   nscoord aBlockHeight,
  2428                   float aFontSizeInflation)
  2430   const nsStyleCoord& lhCoord = aStyleContext->StyleText()->mLineHeight;
  2432   if (lhCoord.GetUnit() == eStyleUnit_Coord) {
  2433     nscoord result = lhCoord.GetCoordValue();
  2434     if (aFontSizeInflation != 1.0f) {
  2435       result = NSToCoordRound(result * aFontSizeInflation);
  2437     return result;
  2440   if (lhCoord.GetUnit() == eStyleUnit_Factor)
  2441     // For factor units the computed value of the line-height property 
  2442     // is found by multiplying the factor by the font's computed size
  2443     // (adjusted for min-size prefs and text zoom).
  2444     return NSToCoordRound(lhCoord.GetFactorValue() * aFontSizeInflation *
  2445                           aStyleContext->StyleFont()->mFont.size);
  2447   NS_ASSERTION(lhCoord.GetUnit() == eStyleUnit_Normal ||
  2448                lhCoord.GetUnit() == eStyleUnit_Enumerated,
  2449                "bad line-height unit");
  2451   if (lhCoord.GetUnit() == eStyleUnit_Enumerated) {
  2452     NS_ASSERTION(lhCoord.GetIntValue() == NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT,
  2453                  "bad line-height value");
  2454     if (aBlockHeight != NS_AUTOHEIGHT) {
  2455       return aBlockHeight;
  2459   nsRefPtr<nsFontMetrics> fm;
  2460   nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext,
  2461                                                getter_AddRefs(fm),
  2462                                                aFontSizeInflation);
  2463   return GetNormalLineHeight(fm);
  2466 nscoord
  2467 nsHTMLReflowState::CalcLineHeight() const
  2469   nscoord blockHeight =
  2470     nsLayoutUtils::IsNonWrapperBlock(frame) ? ComputedHeight() :
  2471     (mCBReflowState ? mCBReflowState->ComputedHeight() : NS_AUTOHEIGHT);
  2473   return CalcLineHeight(frame->GetContent(), frame->StyleContext(), blockHeight,
  2474                         nsLayoutUtils::FontSizeInflationFor(frame));
  2477 /* static */ nscoord
  2478 nsHTMLReflowState::CalcLineHeight(nsIContent* aContent,
  2479                                   nsStyleContext* aStyleContext,
  2480                                   nscoord aBlockHeight,
  2481                                   float aFontSizeInflation)
  2483   NS_PRECONDITION(aStyleContext, "Must have a style context");
  2485   nscoord lineHeight =
  2486     ComputeLineHeight(aStyleContext, aBlockHeight, aFontSizeInflation);
  2488   NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up");
  2490   HTMLInputElement* input = HTMLInputElement::FromContentOrNull(aContent);
  2491   if (input && input->IsSingleLineTextControl()) {
  2492     // For Web-compatibility, single-line text input elements cannot
  2493     // have a line-height smaller than one.
  2494     nscoord lineHeightOne =
  2495       aFontSizeInflation * aStyleContext->StyleFont()->mFont.size;
  2496     if (lineHeight < lineHeightOne) {
  2497       lineHeight = lineHeightOne;
  2501   return lineHeight;
  2504 bool
  2505 nsCSSOffsetState::ComputeMargin(nscoord aHorizontalPercentBasis,
  2506                                 nscoord aVerticalPercentBasis)
  2508   // SVG text frames have no margin.
  2509   if (frame->IsSVGText()) {
  2510     return false;
  2513   // If style style can provide us the margin directly, then use it.
  2514   const nsStyleMargin *styleMargin = frame->StyleMargin();
  2515   bool isCBDependent = !styleMargin->GetMargin(ComputedPhysicalMargin());
  2516   if (isCBDependent) {
  2517     // We have to compute the value
  2518     ComputedPhysicalMargin().left = nsLayoutUtils::
  2519       ComputeCBDependentValue(aHorizontalPercentBasis,
  2520                               styleMargin->mMargin.GetLeft());
  2521     ComputedPhysicalMargin().right = nsLayoutUtils::
  2522       ComputeCBDependentValue(aHorizontalPercentBasis,
  2523                               styleMargin->mMargin.GetRight());
  2525     ComputedPhysicalMargin().top = nsLayoutUtils::
  2526       ComputeCBDependentValue(aVerticalPercentBasis,
  2527                               styleMargin->mMargin.GetTop());
  2528     ComputedPhysicalMargin().bottom = nsLayoutUtils::
  2529       ComputeCBDependentValue(aVerticalPercentBasis,
  2530                               styleMargin->mMargin.GetBottom());
  2533   nscoord marginAdjustment = FontSizeInflationListMarginAdjustment(frame);
  2535   if (marginAdjustment > 0) {
  2536     const nsStyleVisibility* visibility = frame->StyleVisibility();
  2537     if (visibility->mDirection == NS_STYLE_DIRECTION_RTL) {
  2538       ComputedPhysicalMargin().right = ComputedPhysicalMargin().right + marginAdjustment;
  2539     } else {
  2540       ComputedPhysicalMargin().left = ComputedPhysicalMargin().left + marginAdjustment;
  2544   return isCBDependent;
  2547 bool
  2548 nsCSSOffsetState::ComputePadding(nscoord aHorizontalPercentBasis,
  2549                                  nscoord aVerticalPercentBasis,
  2550                                  nsIAtom* aFrameType)
  2552   // If style can provide us the padding directly, then use it.
  2553   const nsStylePadding *stylePadding = frame->StylePadding();
  2554   bool isCBDependent = !stylePadding->GetPadding(ComputedPhysicalPadding());
  2555   // a table row/col group, row/col doesn't have padding
  2556   // XXXldb Neither do border-collapse tables.
  2557   if (nsGkAtoms::tableRowGroupFrame == aFrameType ||
  2558       nsGkAtoms::tableColGroupFrame == aFrameType ||
  2559       nsGkAtoms::tableRowFrame      == aFrameType ||
  2560       nsGkAtoms::tableColFrame      == aFrameType) {
  2561     ComputedPhysicalPadding().SizeTo(0,0,0,0);
  2563   else if (isCBDependent) {
  2564     // We have to compute the value
  2565     // clamp negative calc() results to 0
  2566     ComputedPhysicalPadding().left = std::max(0, nsLayoutUtils::
  2567       ComputeCBDependentValue(aHorizontalPercentBasis,
  2568                               stylePadding->mPadding.GetLeft()));
  2569     ComputedPhysicalPadding().right = std::max(0, nsLayoutUtils::
  2570       ComputeCBDependentValue(aHorizontalPercentBasis,
  2571                               stylePadding->mPadding.GetRight()));
  2573     ComputedPhysicalPadding().top = std::max(0, nsLayoutUtils::
  2574       ComputeCBDependentValue(aVerticalPercentBasis,
  2575                               stylePadding->mPadding.GetTop()));
  2576     ComputedPhysicalPadding().bottom = std::max(0, nsLayoutUtils::
  2577       ComputeCBDependentValue(aVerticalPercentBasis,
  2578                               stylePadding->mPadding.GetBottom()));
  2580   return isCBDependent;
  2583 void
  2584 nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth,
  2585                                        nscoord aContainingBlockHeight,
  2586                                        const nsHTMLReflowState* aContainingBlockRS)
  2588   ComputedMinWidth() = ComputeWidthValue(aContainingBlockWidth,
  2589                                         mStylePosition->mBoxSizing,
  2590                                         mStylePosition->mMinWidth);
  2592   if (eStyleUnit_None == mStylePosition->mMaxWidth.GetUnit()) {
  2593     // Specified value of 'none'
  2594     ComputedMaxWidth() = NS_UNCONSTRAINEDSIZE;  // no limit
  2595   } else {
  2596     ComputedMaxWidth() = ComputeWidthValue(aContainingBlockWidth,
  2597                                           mStylePosition->mBoxSizing,
  2598                                           mStylePosition->mMaxWidth);
  2601   // If the computed value of 'min-width' is greater than the value of
  2602   // 'max-width', 'max-width' is set to the value of 'min-width'
  2603   if (ComputedMinWidth() > ComputedMaxWidth()) {
  2604     ComputedMaxWidth() = ComputedMinWidth();
  2607   // Check for percentage based values and a containing block height that
  2608   // depends on the content height. Treat them like 'auto'
  2609   // Likewise, check for calc() with percentages on internal table elements;
  2610   // that's treated as 'auto' too.
  2611   // Likewise, if we're a child of a flex container who's measuring our
  2612   // intrinsic height, then we want to disregard our min-height.
  2614   const nsStyleCoord &minHeight = mStylePosition->mMinHeight;
  2615   if ((NS_AUTOHEIGHT == aContainingBlockHeight &&
  2616        minHeight.HasPercent()) ||
  2617       (mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE &&
  2618        minHeight.IsCalcUnit() && minHeight.CalcHasPercent()) ||
  2619       mFlags.mIsFlexContainerMeasuringHeight) {
  2620     ComputedMinHeight() = 0;
  2621   } else {
  2622     ComputedMinHeight() = ComputeHeightValue(aContainingBlockHeight, 
  2623                                             mStylePosition->mBoxSizing, 
  2624                                             minHeight);
  2626   const nsStyleCoord &maxHeight = mStylePosition->mMaxHeight;
  2627   nsStyleUnit maxHeightUnit = maxHeight.GetUnit();
  2628   if (eStyleUnit_None == maxHeightUnit) {
  2629     // Specified value of 'none'
  2630     ComputedMaxHeight() = NS_UNCONSTRAINEDSIZE;  // no limit
  2631   } else {
  2632     // Check for percentage based values and a containing block height that
  2633     // depends on the content height. Treat them like 'none'
  2634     // Likewise, check for calc() with percentages on internal table elements;
  2635     // that's treated as 'auto' too.
  2636     // Likewise, if we're a child of a flex container who's measuring our
  2637     // intrinsic height, then we want to disregard our max-height.
  2638     if ((NS_AUTOHEIGHT == aContainingBlockHeight && 
  2639          maxHeight.HasPercent()) ||
  2640         (mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE &&
  2641          maxHeight.IsCalcUnit() && maxHeight.CalcHasPercent()) ||
  2642         mFlags.mIsFlexContainerMeasuringHeight) {
  2643       ComputedMaxHeight() = NS_UNCONSTRAINEDSIZE;
  2644     } else {
  2645       ComputedMaxHeight() = ComputeHeightValue(aContainingBlockHeight, 
  2646                                               mStylePosition->mBoxSizing,
  2647                                               maxHeight);
  2651   // If the computed value of 'min-height' is greater than the value of
  2652   // 'max-height', 'max-height' is set to the value of 'min-height'
  2653   if (ComputedMinHeight() > ComputedMaxHeight()) {
  2654     ComputedMaxHeight() = ComputedMinHeight();
  2658 void
  2659 nsHTMLReflowState::SetTruncated(const nsHTMLReflowMetrics& aMetrics,
  2660                                 nsReflowStatus* aStatus) const
  2662   if (AvailableHeight() != NS_UNCONSTRAINEDSIZE &&
  2663       AvailableHeight() < aMetrics.Height() &&
  2664       !mFlags.mIsTopOfPage) {
  2665     *aStatus |= NS_FRAME_TRUNCATED;
  2666   } else {
  2667     *aStatus &= ~NS_FRAME_TRUNCATED;
  2671 bool
  2672 nsHTMLReflowState::IsFloating() const
  2674   return mStyleDisplay->IsFloating(frame);
  2677 uint8_t
  2678 nsHTMLReflowState::GetDisplay() const
  2680   return mStyleDisplay->GetDisplay(frame);

mercurial