LCOV - code coverage report
Current view: directory - layout/generic - nsHTMLReflowState.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 886 0 0.0 %
Date: 2012-06-02 Functions: 41 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Mats Palmgren <matspal@gmail.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : /* struct containing the input to nsIFrame::Reflow */
      40                 : 
      41                 : #include "nsCOMPtr.h"
      42                 : #include "nsStyleConsts.h"
      43                 : #include "nsCSSAnonBoxes.h"
      44                 : #include "nsFrame.h"
      45                 : #include "nsIContent.h"
      46                 : #include "nsGkAtoms.h"
      47                 : #include "nsPresContext.h"
      48                 : #include "nsIPresShell.h"
      49                 : #include "nsFontMetrics.h"
      50                 : #include "nsBlockFrame.h"
      51                 : #include "nsLineBox.h"
      52                 : #include "nsImageFrame.h"
      53                 : #include "nsTableFrame.h"
      54                 : #include "nsTableCellFrame.h"
      55                 : #include "nsIServiceManager.h"
      56                 : #include "nsIPercentHeightObserver.h"
      57                 : #include "nsLayoutUtils.h"
      58                 : #include "mozilla/Preferences.h"
      59                 : #ifdef IBMBIDI
      60                 : #include "nsBidiUtils.h"
      61                 : #endif
      62                 : 
      63                 : #ifdef NS_DEBUG
      64                 : #undef NOISY_VERTICAL_ALIGN
      65                 : #else
      66                 : #undef NOISY_VERTICAL_ALIGN
      67                 : #endif
      68                 : 
      69                 : using namespace mozilla;
      70                 : using namespace mozilla::layout;
      71                 : 
      72                 : // Prefs-driven control for |text-decoration: blink|
      73                 : static bool sPrefIsLoaded = false;
      74                 : static bool sBlinkIsAllowed = true;
      75                 : 
      76                 : enum eNormalLineHeightControl {
      77                 :   eUninitialized = -1,
      78                 :   eNoExternalLeading = 0,   // does not include external leading 
      79                 :   eIncludeExternalLeading,  // use whatever value font vendor provides
      80                 :   eCompensateLeading        // compensate leading if leading provided by font vendor is not enough
      81                 : };
      82                 : 
      83                 : static eNormalLineHeightControl sNormalLineHeightControl = eUninitialized;
      84                 : 
      85                 : // Initialize a <b>root</b> reflow state with a rendering context to
      86                 : // use for measuring things.
      87               0 : nsHTMLReflowState::nsHTMLReflowState(nsPresContext*       aPresContext,
      88                 :                                      nsIFrame*            aFrame,
      89                 :                                      nsRenderingContext* aRenderingContext,
      90                 :                                      const nsSize&        aAvailableSpace)
      91                 :   : nsCSSOffsetState(aFrame, aRenderingContext)
      92                 :   , mBlockDelta(0)
      93                 :   , mReflowDepth(0)
      94                 :   , mRestoreCurrentInflationContainer(aPresContext->mCurrentInflationContainer)
      95                 :   , mRestoreCurrentInflationContainerWidth(aPresContext->
      96               0 :                                              mCurrentInflationContainerWidth)
      97                 : {
      98               0 :   NS_PRECONDITION(aPresContext, "no pres context");
      99               0 :   NS_PRECONDITION(aRenderingContext, "no rendering context");
     100               0 :   NS_PRECONDITION(aFrame, "no frame");
     101               0 :   parentReflowState = nsnull;
     102               0 :   availableWidth = aAvailableSpace.width;
     103               0 :   availableHeight = aAvailableSpace.height;
     104               0 :   mFloatManager = nsnull;
     105               0 :   mLineLayout = nsnull;
     106               0 :   memset(&mFlags, 0, sizeof(mFlags));
     107               0 :   mDiscoveredClearance = nsnull;
     108               0 :   mPercentHeightObserver = nsnull;
     109               0 :   Init(aPresContext);
     110               0 : }
     111                 : 
     112               0 : static bool CheckNextInFlowParenthood(nsIFrame* aFrame, nsIFrame* aParent)
     113                 : {
     114               0 :   nsIFrame* frameNext = aFrame->GetNextInFlow();
     115               0 :   nsIFrame* parentNext = aParent->GetNextInFlow();
     116               0 :   return frameNext && parentNext && frameNext->GetParent() == parentNext;
     117                 : }
     118                 : 
     119                 : // Initialize a reflow state for a child frames reflow. Some state
     120                 : // is copied from the parent reflow state; the remaining state is
     121                 : // computed.
     122               0 : nsHTMLReflowState::nsHTMLReflowState(nsPresContext*           aPresContext,
     123                 :                                      const nsHTMLReflowState& aParentReflowState,
     124                 :                                      nsIFrame*                aFrame,
     125                 :                                      const nsSize&            aAvailableSpace,
     126                 :                                      nscoord                  aContainingBlockWidth,
     127                 :                                      nscoord                  aContainingBlockHeight,
     128                 :                                      bool                     aInit)
     129                 :   : nsCSSOffsetState(aFrame, aParentReflowState.rendContext)
     130                 :   , mBlockDelta(0)
     131                 :   , mReflowDepth(aParentReflowState.mReflowDepth + 1)
     132                 :   , mFlags(aParentReflowState.mFlags)
     133                 :   , mRestoreCurrentInflationContainer(aPresContext->mCurrentInflationContainer)
     134                 :   , mRestoreCurrentInflationContainerWidth(aPresContext->
     135               0 :                                              mCurrentInflationContainerWidth)
     136                 : {
     137               0 :   NS_PRECONDITION(aPresContext, "no pres context");
     138               0 :   NS_PRECONDITION(aFrame, "no frame");
     139               0 :   NS_PRECONDITION((aContainingBlockWidth == -1) ==
     140                 :                     (aContainingBlockHeight == -1),
     141                 :                   "cb width and height should only be non-default together");
     142               0 :   NS_PRECONDITION(!mFlags.mSpecialHeightReflow ||
     143                 :                   !NS_SUBTREE_DIRTY(aFrame),
     144                 :                   "frame should be clean when getting special height reflow");
     145                 : 
     146               0 :   parentReflowState = &aParentReflowState;
     147                 : 
     148                 :   // If the parent is dirty, then the child is as well.
     149                 :   // XXX Are the other cases where the parent reflows a child a second
     150                 :   // time, as a resize?
     151               0 :   if (!mFlags.mSpecialHeightReflow)
     152               0 :     frame->AddStateBits(parentReflowState->frame->GetStateBits() &
     153               0 :                         NS_FRAME_IS_DIRTY);
     154                 : 
     155               0 :   availableWidth = aAvailableSpace.width;
     156               0 :   availableHeight = aAvailableSpace.height;
     157                 : 
     158               0 :   mFloatManager = aParentReflowState.mFloatManager;
     159               0 :   if (frame->IsFrameOfType(nsIFrame::eLineParticipant))
     160               0 :     mLineLayout = aParentReflowState.mLineLayout;
     161                 :   else
     162               0 :     mLineLayout = nsnull;
     163                 : 
     164                 :   // Note: mFlags was initialized as a copy of aParentReflowState.mFlags up in
     165                 :   // this constructor's init list, so the only flags that we need to explicitly
     166                 :   // initialize here are those that may need a value other than our parent's.
     167                 :   mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
     168               0 :     CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
     169               0 :   mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false;
     170               0 :   mFlags.mHasClearance = false;
     171               0 :   mFlags.mIsColumnBalancing = false;
     172                 : 
     173               0 :   mDiscoveredClearance = nsnull;
     174                 :   mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && 
     175               0 :                             aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) 
     176               0 :                            ? aParentReflowState.mPercentHeightObserver : nsnull;
     177                 : 
     178               0 :   if (aInit) {
     179               0 :     Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight);
     180                 :   }
     181               0 : }
     182                 : 
     183                 : inline nscoord
     184               0 : nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth,
     185                 :                                     nscoord aContentEdgeToBoxSizing,
     186                 :                                     nscoord aBoxSizingToMarginEdge,
     187                 :                                     const nsStyleCoord& aCoord)
     188                 : {
     189                 :   return nsLayoutUtils::ComputeWidthValue(rendContext, frame,
     190                 :                                           aContainingBlockWidth,
     191                 :                                           aContentEdgeToBoxSizing,
     192                 :                                           aBoxSizingToMarginEdge,
     193               0 :                                           aCoord);
     194                 : }
     195                 : 
     196                 : nscoord
     197               0 : nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth,
     198                 :                                     PRUint8 aBoxSizing,
     199                 :                                     const nsStyleCoord& aCoord)
     200                 : {
     201               0 :   nscoord inside = 0, outside = mComputedBorderPadding.LeftRight() +
     202               0 :                                 mComputedMargin.LeftRight();
     203               0 :   switch (aBoxSizing) {
     204                 :     case NS_STYLE_BOX_SIZING_BORDER:
     205               0 :       inside = mComputedBorderPadding.LeftRight();
     206               0 :       break;
     207                 :     case NS_STYLE_BOX_SIZING_PADDING:
     208               0 :       inside = mComputedPadding.LeftRight();
     209               0 :       break;
     210                 :   }
     211               0 :   outside -= inside;
     212                 : 
     213                 :   return ComputeWidthValue(aContainingBlockWidth, inside,
     214               0 :                            outside, aCoord);
     215                 : }
     216                 : 
     217                 : void
     218               0 : nsHTMLReflowState::SetComputedWidth(nscoord aComputedWidth)
     219                 : {
     220               0 :   NS_ASSERTION(frame, "Must have a frame!");
     221                 :   // It'd be nice to assert that |frame| is not in reflow, but this fails for
     222                 :   // two reasons:
     223                 :   //
     224                 :   // 1) Viewport frames reset the computed width on a copy of their reflow
     225                 :   //    state when reflowing fixed-pos kids.  In that case we actually don't
     226                 :   //    want to mess with the resize flags, because comparing the frame's rect
     227                 :   //    to the munged computed width is pointless.
     228                 :   // 2) nsFrame::BoxReflow creates a reflow state for its parent.  This reflow
     229                 :   //    state is not used to reflow the parent, but just as a parent for the
     230                 :   //    frame's own reflow state.  So given a nsBoxFrame inside some non-XUL
     231                 :   //    (like a text control, for example), we'll end up creating a reflow
     232                 :   //    state for the parent while the parent is reflowing.
     233                 : 
     234               0 :   NS_PRECONDITION(aComputedWidth >= 0, "Invalid computed width");
     235               0 :   if (mComputedWidth != aComputedWidth) {
     236               0 :     mComputedWidth = aComputedWidth;
     237               0 :     nsIAtom* frameType = frame->GetType();
     238               0 :     if (frameType != nsGkAtoms::viewportFrame) { // Or check GetParent()?
     239               0 :       InitResizeFlags(frame->PresContext(), frameType);
     240                 :     }
     241                 :   }
     242               0 : }
     243                 : 
     244                 : void
     245               0 : nsHTMLReflowState::SetComputedHeight(nscoord aComputedHeight)
     246                 : {
     247               0 :   NS_ASSERTION(frame, "Must have a frame!");
     248                 :   // It'd be nice to assert that |frame| is not in reflow, but this fails
     249                 :   // because:
     250                 :   //
     251                 :   //    nsFrame::BoxReflow creates a reflow state for its parent.  This reflow
     252                 :   //    state is not used to reflow the parent, but just as a parent for the
     253                 :   //    frame's own reflow state.  So given a nsBoxFrame inside some non-XUL
     254                 :   //    (like a text control, for example), we'll end up creating a reflow
     255                 :   //    state for the parent while the parent is reflowing.
     256                 : 
     257               0 :   NS_PRECONDITION(aComputedHeight >= 0, "Invalid computed height");
     258               0 :   if (mComputedHeight != aComputedHeight) {
     259               0 :     mComputedHeight = aComputedHeight;
     260               0 :     InitResizeFlags(frame->PresContext(), frame->GetType());
     261                 :   }
     262               0 : }
     263                 : 
     264                 : void
     265               0 : nsHTMLReflowState::Init(nsPresContext* aPresContext,
     266                 :                         nscoord         aContainingBlockWidth,
     267                 :                         nscoord         aContainingBlockHeight,
     268                 :                         const nsMargin* aBorder,
     269                 :                         const nsMargin* aPadding)
     270                 : {
     271               0 :   NS_WARN_IF_FALSE(availableWidth != NS_UNCONSTRAINEDSIZE,
     272                 :                    "have unconstrained width; this should only result from "
     273                 :                    "very large sizes, not attempts at intrinsic width "
     274                 :                    "calculation");
     275                 : 
     276               0 :   mStylePosition = frame->GetStylePosition();
     277               0 :   mStyleDisplay = frame->GetStyleDisplay();
     278               0 :   mStyleVisibility = frame->GetStyleVisibility();
     279               0 :   mStyleBorder = frame->GetStyleBorder();
     280               0 :   mStyleMargin = frame->GetStyleMargin();
     281               0 :   mStylePadding = frame->GetStylePadding();
     282               0 :   mStyleText = frame->GetStyleText();
     283                 : 
     284               0 :   nsIAtom* type = frame->GetType();
     285                 : 
     286               0 :   InitFrameType(type);
     287               0 :   InitCBReflowState();
     288                 : 
     289                 :   InitConstraints(aPresContext, aContainingBlockWidth, aContainingBlockHeight,
     290               0 :                   aBorder, aPadding, type);
     291                 : 
     292               0 :   InitResizeFlags(aPresContext, type);
     293                 : 
     294               0 :   nsIFrame *parent = frame->GetParent();
     295               0 :   if (parent &&
     296               0 :       (parent->GetStateBits() & NS_FRAME_IN_CONSTRAINED_HEIGHT) &&
     297               0 :       !(parent->GetType() == nsGkAtoms::scrollFrame &&
     298               0 :         parent->GetStyleDisplay()->mOverflowY != NS_STYLE_OVERFLOW_HIDDEN)) {
     299               0 :     frame->AddStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
     300               0 :   } else if ((mStylePosition->mHeight.GetUnit() != eStyleUnit_Auto ||
     301               0 :               mStylePosition->mMaxHeight.GetUnit() != eStyleUnit_None) &&
     302                 :               // Don't set NS_FRAME_IN_CONSTRAINED_HEIGHT on body or html
     303                 :               // elements.
     304               0 :              (frame->GetContent() &&
     305               0 :             !(frame->GetContent()->IsHTML(nsGkAtoms::body) ||
     306               0 :               frame->GetContent()->IsHTML(nsGkAtoms::html)))) {
     307               0 :     frame->AddStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
     308                 :   } else {
     309               0 :     frame->RemoveStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
     310                 :   }
     311                 : 
     312               0 :   NS_WARN_IF_FALSE((mFrameType == NS_CSS_FRAME_TYPE_INLINE &&
     313                 :                     !frame->IsFrameOfType(nsIFrame::eReplaced)) ||
     314                 :                    type == nsGkAtoms::textFrame ||
     315                 :                    mComputedWidth != NS_UNCONSTRAINEDSIZE,
     316                 :                    "have unconstrained width; this should only result from "
     317                 :                    "very large sizes, not attempts at intrinsic width "
     318                 :                    "calculation");
     319               0 : }
     320                 : 
     321               0 : void nsHTMLReflowState::InitCBReflowState()
     322                 : {
     323               0 :   if (!parentReflowState) {
     324               0 :     mCBReflowState = nsnull;
     325               0 :     return;
     326                 :   }
     327                 : 
     328               0 :   if (parentReflowState->frame == frame->GetContainingBlock()) {
     329                 :     // Inner table frames need to use the containing block of the outer
     330                 :     // table frame.
     331               0 :     if (frame->GetType() == nsGkAtoms::tableFrame) {
     332               0 :       mCBReflowState = parentReflowState->mCBReflowState;
     333                 :     } else {
     334               0 :       mCBReflowState = parentReflowState;
     335                 :     }
     336                 :   } else {
     337               0 :     mCBReflowState = parentReflowState->mCBReflowState;
     338                 :   }
     339                 : }
     340                 : 
     341                 : /* Check whether CalcQuirkContainingBlockHeight would stop on the
     342                 :  * given reflow state, using its block as a height.  (essentially 
     343                 :  * returns false for any case in which CalcQuirkContainingBlockHeight 
     344                 :  * has a "continue" in its main loop.)
     345                 :  *
     346                 :  * XXX Maybe refactor CalcQuirkContainingBlockHeight so it uses 
     347                 :  * this function as well
     348                 :  */
     349                 : static bool
     350               0 : IsQuirkContainingBlockHeight(const nsHTMLReflowState* rs, nsIAtom* aFrameType)
     351                 : {
     352               0 :   if (nsGkAtoms::blockFrame == aFrameType ||
     353                 : #ifdef MOZ_XUL
     354                 :       nsGkAtoms::XULLabelFrame == aFrameType ||
     355                 : #endif
     356                 :       nsGkAtoms::scrollFrame == aFrameType) {
     357                 :     // Note: This next condition could change due to a style change,
     358                 :     // but that would cause a style reflow anyway, which means we're ok.
     359               0 :     if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
     360               0 :       if (!rs->frame->GetStyleDisplay()->IsAbsolutelyPositioned()) {
     361               0 :         return false;
     362                 :       }
     363                 :     }
     364                 :   }
     365               0 :   return true;
     366                 : }
     367                 : 
     368                 : 
     369                 : void
     370               0 : nsHTMLReflowState::InitResizeFlags(nsPresContext* aPresContext, nsIAtom* aFrameType)
     371                 : {
     372               0 :   mFlags.mHResize = !(frame->GetStateBits() & NS_FRAME_IS_DIRTY) &&
     373               0 :                     frame->GetSize().width !=
     374               0 :                       mComputedWidth + mComputedBorderPadding.LeftRight();
     375               0 :   if (mFlags.mHResize &&
     376               0 :       nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
     377                 :     // When font size inflation is enabled, the change in the width of a
     378                 :     // block (or anything that returns true in
     379                 :     // IsContainerForFontSizeInflation) needs to cause a dirty reflow
     380                 :     // since it changes the size of text, line-heights, etc.  This is
     381                 :     // relatively similar to a classic case of style change reflow,
     382                 :     // except that because inflation doesn't affect the intrinsic sizing
     383                 :     // codepath, there's no need to invalidate intrinsic sizes.
     384                 :     //
     385                 :     // Note that this makes horizontal resizing a good bit more
     386                 :     // expensive.  However, font size inflation is targeted at a set of
     387                 :     // devices (zoom-and-pan devices) where the main use case for
     388                 :     // horizontal resizing needing to be efficient (window resizing) is
     389                 :     // not present.  It does still increase the cost of dynamic changes
     390                 :     // caused by script where a style or content change in one place
     391                 :     // causes a resize in another (e.g., rebalancing a table).
     392                 : 
     393                 :     // FIXME: This isn't so great for the cases where
     394                 :     // nsHTMLReflowState::SetComputedWith is called, if the first time
     395                 :     // we go through InitResizeFlags we set mHResize to true, and then
     396                 :     // the second time we'd set it to false even without the
     397                 :     // NS_FRAME_IS_DIRTY bit already set.
     398               0 :     frame->AddStateBits(NS_FRAME_IS_DIRTY);
     399                 :   }
     400                 : 
     401                 :   // XXX Should we really need to null check mCBReflowState?  (We do for
     402                 :   // at least nsBoxFrame).
     403               0 :   if (IS_TABLE_CELL(aFrameType) &&
     404                 :       (mFlags.mSpecialHeightReflow ||
     405               0 :        (frame->GetFirstInFlow()->GetStateBits() &
     406                 :          NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) &&
     407               0 :       (frame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
     408                 :     // Need to set the bit on the cell so that
     409                 :     // mCBReflowState->mFlags.mVResize is set correctly below when
     410                 :     // reflowing descendant.
     411               0 :     mFlags.mVResize = true;
     412               0 :   } else if (mCBReflowState && !nsLayoutUtils::IsNonWrapperBlock(frame)) {
     413                 :     // XXX Is this problematic for relatively positioned inlines acting
     414                 :     // as containing block for absolutely positioned elements?
     415                 :     // Possibly; in that case we should at least be checking
     416                 :     // NS_SUBTREE_DIRTY, I'd think.
     417               0 :     mFlags.mVResize = mCBReflowState->mFlags.mVResize;
     418               0 :   } else if (mComputedHeight == NS_AUTOHEIGHT) {
     419               0 :     if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
     420                 :         mCBReflowState) {
     421               0 :       mFlags.mVResize = mCBReflowState->mFlags.mVResize;
     422                 :     } else {
     423               0 :       mFlags.mVResize = mFlags.mHResize;
     424                 :     }
     425               0 :     mFlags.mVResize = mFlags.mVResize || NS_SUBTREE_DIRTY(frame);
     426                 :   } else {
     427                 :     // not 'auto' height
     428               0 :     mFlags.mVResize = frame->GetSize().height !=
     429               0 :                         mComputedHeight + mComputedBorderPadding.TopBottom();
     430                 :   }
     431                 : 
     432                 :   bool dependsOnCBHeight =
     433               0 :     (mStylePosition->HeightDependsOnContainer() &&
     434                 :      // FIXME: condition this on not-abspos?
     435               0 :      mStylePosition->mHeight.GetUnit() != eStyleUnit_Auto) ||
     436               0 :     (mStylePosition->MinHeightDependsOnContainer() &&
     437                 :      // FIXME: condition this on not-abspos?
     438               0 :      mStylePosition->mMinHeight.GetUnit() != eStyleUnit_Auto) ||
     439               0 :     (mStylePosition->MaxHeightDependsOnContainer() &&
     440                 :      // FIXME: condition this on not-abspos?
     441               0 :      mStylePosition->mMaxHeight.GetUnit() != eStyleUnit_Auto) ||
     442               0 :     mStylePosition->OffsetHasPercent(NS_SIDE_TOP) ||
     443               0 :     mStylePosition->mOffset.GetBottomUnit() != eStyleUnit_Auto ||
     444               0 :     frame->IsBoxFrame();
     445                 : 
     446               0 :   if (mStyleText->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
     447               0 :     NS_ASSERTION(mStyleText->mLineHeight.GetIntValue() ==
     448                 :                  NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT,
     449                 :                  "bad line-height value");
     450                 : 
     451                 :     // line-height depends on block height
     452               0 :     frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
     453                 :     // but only on containing blocks if this frame is not a suitable block
     454               0 :     dependsOnCBHeight |= !nsLayoutUtils::IsNonWrapperBlock(frame);
     455                 :   }
     456                 : 
     457                 :   // If we're the descendant of a table cell that performs special height
     458                 :   // reflows and we could be the child that requires them, always set
     459                 :   // the vertical resize in case this is the first pass before the
     460                 :   // special height reflow.  However, don't do this if it actually is
     461                 :   // the special height reflow, since in that case it will already be
     462                 :   // set correctly above if we need it set.
     463               0 :   if (!mFlags.mVResize && mCBReflowState &&
     464               0 :       (IS_TABLE_CELL(mCBReflowState->frame->GetType()) || 
     465                 :        mCBReflowState->mFlags.mHeightDependsOnAncestorCell) &&
     466               0 :       !mCBReflowState->mFlags.mSpecialHeightReflow && 
     467                 :       dependsOnCBHeight) {
     468               0 :     mFlags.mVResize = true;
     469               0 :     mFlags.mHeightDependsOnAncestorCell = true;
     470                 :   }
     471                 : 
     472                 :   // Set NS_FRAME_CONTAINS_RELATIVE_HEIGHT if it's needed.
     473                 : 
     474                 :   // It would be nice to check that |mComputedHeight != NS_AUTOHEIGHT|
     475                 :   // &&ed with the percentage height check.  However, this doesn't get
     476                 :   // along with table special height reflows, since a special height
     477                 :   // reflow (a quirk that makes such percentage heights work on children
     478                 :   // of table cells) can cause not just a single percentage height to
     479                 :   // become fixed, but an entire descendant chain of percentage heights
     480                 :   // to become fixed.
     481               0 :   if (dependsOnCBHeight && mCBReflowState) {
     482               0 :     const nsHTMLReflowState *rs = this;
     483               0 :     bool hitCBReflowState = false;
     484               0 :     do {
     485               0 :       rs = rs->parentReflowState;
     486               0 :       if (!rs) {
     487               0 :         break;
     488                 :       }
     489                 :         
     490               0 :       if (rs->frame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)
     491               0 :         break; // no need to go further
     492               0 :       rs->frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
     493                 :       
     494                 :       // Keep track of whether we've hit the containing block, because
     495                 :       // we need to go at least that far.
     496               0 :       if (rs == mCBReflowState) {
     497               0 :         hitCBReflowState = true;
     498                 :       }
     499                 : 
     500               0 :     } while (!hitCBReflowState ||
     501               0 :              (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
     502               0 :               !IsQuirkContainingBlockHeight(rs, rs->frame->GetType())));
     503                 :     // Note: We actually don't need to set the
     504                 :     // NS_FRAME_CONTAINS_RELATIVE_HEIGHT bit for the cases
     505                 :     // where we hit the early break statements in
     506                 :     // CalcQuirkContainingBlockHeight. But it doesn't hurt
     507                 :     // us to set the bit in these cases.
     508                 :     
     509                 :   }
     510               0 :   if (frame->GetStateBits() & NS_FRAME_IS_DIRTY) {
     511                 :     // If we're reflowing everything, then we'll find out if we need
     512                 :     // to re-set this.
     513               0 :     frame->RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
     514                 :   }
     515               0 : }
     516                 : 
     517                 : /* static */
     518                 : nscoord
     519               0 : nsHTMLReflowState::GetContainingBlockContentWidth(const nsHTMLReflowState* aReflowState)
     520                 : {
     521               0 :   const nsHTMLReflowState* rs = aReflowState->mCBReflowState;
     522               0 :   if (!rs)
     523               0 :     return 0;
     524               0 :   return rs->mComputedWidth;
     525                 : }
     526                 : 
     527                 : void
     528               0 : nsHTMLReflowState::InitFrameType(nsIAtom* aFrameType)
     529                 : {
     530               0 :   const nsStyleDisplay *disp = mStyleDisplay;
     531                 :   nsCSSFrameType frameType;
     532                 : 
     533                 :   // Section 9.7 of the CSS2 spec indicates that absolute position
     534                 :   // takes precedence over float which takes precedence over display.
     535                 :   // XXXldb nsRuleNode::ComputeDisplayData should take care of this, right?
     536                 :   // Make sure the frame was actually moved out of the flow, and don't
     537                 : 
     538                 :   // just assume what the style says, because we might not have had a
     539                 :   // useful float/absolute containing block
     540                 : 
     541               0 :   DISPLAY_INIT_TYPE(frame, this);
     542                 : 
     543               0 :   if (aFrameType == nsGkAtoms::tableFrame) {
     544               0 :     mFrameType = NS_CSS_FRAME_TYPE_BLOCK;
     545                 :     return;
     546                 :   }
     547                 : 
     548               0 :   NS_ASSERTION(frame->GetStyleDisplay()->IsAbsolutelyPositioned() ==
     549                 :                  disp->IsAbsolutelyPositioned(),
     550                 :                "Unexpected position style");
     551               0 :   NS_ASSERTION(frame->GetStyleDisplay()->IsFloating() ==
     552                 :                  disp->IsFloating(), "Unexpected float style");
     553               0 :   if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
     554               0 :     if (disp->IsAbsolutelyPositioned()) {
     555               0 :       frameType = NS_CSS_FRAME_TYPE_ABSOLUTE;
     556                 :       //XXXfr hack for making frames behave properly when in overflow container lists
     557                 :       //      see bug 154892; need to revisit later
     558               0 :       if (frame->GetPrevInFlow())
     559               0 :         frameType = NS_CSS_FRAME_TYPE_BLOCK;
     560                 :     }
     561               0 :     else if (disp->IsFloating()) {
     562               0 :       frameType = NS_CSS_FRAME_TYPE_FLOATING;
     563                 :     } else {
     564               0 :       NS_ASSERTION(disp->mDisplay == NS_STYLE_DISPLAY_POPUP,
     565                 :                    "unknown out of flow frame type");
     566               0 :       frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
     567                 :     }
     568                 :   }
     569                 :   else {
     570               0 :     switch (disp->mDisplay) {
     571                 :     case NS_STYLE_DISPLAY_BLOCK:
     572                 :     case NS_STYLE_DISPLAY_LIST_ITEM:
     573                 :     case NS_STYLE_DISPLAY_TABLE:
     574                 :     case NS_STYLE_DISPLAY_TABLE_CAPTION:
     575               0 :       frameType = NS_CSS_FRAME_TYPE_BLOCK;
     576               0 :       break;
     577                 : 
     578                 :     case NS_STYLE_DISPLAY_INLINE:
     579                 :     case NS_STYLE_DISPLAY_INLINE_BLOCK:
     580                 :     case NS_STYLE_DISPLAY_INLINE_TABLE:
     581                 :     case NS_STYLE_DISPLAY_INLINE_BOX:
     582                 :     case NS_STYLE_DISPLAY_INLINE_GRID:
     583                 :     case NS_STYLE_DISPLAY_INLINE_STACK:
     584               0 :       frameType = NS_CSS_FRAME_TYPE_INLINE;
     585               0 :       break;
     586                 : 
     587                 :     case NS_STYLE_DISPLAY_TABLE_CELL:
     588                 :     case NS_STYLE_DISPLAY_TABLE_ROW_GROUP:
     589                 :     case NS_STYLE_DISPLAY_TABLE_COLUMN:
     590                 :     case NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP:
     591                 :     case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP:
     592                 :     case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP:
     593                 :     case NS_STYLE_DISPLAY_TABLE_ROW:
     594               0 :       frameType = NS_CSS_FRAME_TYPE_INTERNAL_TABLE;
     595               0 :       break;
     596                 : 
     597                 :     case NS_STYLE_DISPLAY_NONE:
     598                 :     default:
     599               0 :       frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
     600               0 :       break;
     601                 :     }
     602                 :   }
     603                 : 
     604                 :   // See if the frame is replaced
     605               0 :   if (frame->IsFrameOfType(nsIFrame::eReplacedContainsBlock)) {
     606               0 :     frameType = NS_FRAME_REPLACED_CONTAINS_BLOCK(frameType);
     607               0 :   } else if (frame->IsFrameOfType(nsIFrame::eReplaced)) {
     608               0 :     frameType = NS_FRAME_REPLACED(frameType);
     609                 :   }
     610                 : 
     611               0 :   mFrameType = frameType;
     612                 : }
     613                 : 
     614                 : void
     615               0 : nsHTMLReflowState::ComputeRelativeOffsets(const nsHTMLReflowState* cbrs,
     616                 :                                           nscoord aContainingBlockWidth,
     617                 :                                           nscoord aContainingBlockHeight,
     618                 :                                           nsPresContext* aPresContext)
     619                 : {
     620                 :   // Compute the 'left' and 'right' values. 'Left' moves the boxes to the right,
     621                 :   // and 'right' moves the boxes to the left. The computed values are always:
     622                 :   // left=-right
     623               0 :   bool    leftIsAuto = eStyleUnit_Auto == mStylePosition->mOffset.GetLeftUnit();
     624               0 :   bool    rightIsAuto = eStyleUnit_Auto == mStylePosition->mOffset.GetRightUnit();
     625                 : 
     626                 :   // If neither 'left' not 'right' are auto, then we're over-constrained and
     627                 :   // we ignore one of them
     628               0 :   if (!leftIsAuto && !rightIsAuto) {
     629               0 :     if (mCBReflowState &&
     630                 :         NS_STYLE_DIRECTION_RTL == mCBReflowState->mStyleVisibility->mDirection) {
     631               0 :       leftIsAuto = true;
     632                 :     } else {
     633               0 :       rightIsAuto = true;
     634                 :     }
     635                 :   }
     636                 : 
     637               0 :   if (leftIsAuto) {
     638               0 :     if (rightIsAuto) {
     639                 :       // If both are 'auto' (their initial values), the computed values are 0
     640               0 :       mComputedOffsets.left = mComputedOffsets.right = 0;
     641                 :     } else {
     642                 :       // 'Right' isn't 'auto' so compute its value
     643                 :       mComputedOffsets.right = nsLayoutUtils::
     644                 :         ComputeWidthDependentValue(aContainingBlockWidth,
     645               0 :                                    mStylePosition->mOffset.GetRight());
     646                 : 
     647                 :       // Computed value for 'left' is minus the value of 'right'
     648               0 :       mComputedOffsets.left = -mComputedOffsets.right;
     649                 :     }
     650                 : 
     651                 :   } else {
     652               0 :     NS_ASSERTION(rightIsAuto, "unexpected specified constraint");
     653                 :     
     654                 :     // 'Left' isn't 'auto' so compute its value
     655                 :     mComputedOffsets.left = nsLayoutUtils::
     656                 :       ComputeWidthDependentValue(aContainingBlockWidth,
     657               0 :                                  mStylePosition->mOffset.GetLeft());
     658                 : 
     659                 :     // Computed value for 'right' is minus the value of 'left'
     660               0 :     mComputedOffsets.right = -mComputedOffsets.left;
     661                 :   }
     662                 : 
     663                 :   // Compute the 'top' and 'bottom' values. The 'top' and 'bottom' properties
     664                 :   // move relatively positioned elements up and down. They also must be each 
     665                 :   // other's negative
     666               0 :   bool    topIsAuto = eStyleUnit_Auto == mStylePosition->mOffset.GetTopUnit();
     667               0 :   bool    bottomIsAuto = eStyleUnit_Auto == mStylePosition->mOffset.GetBottomUnit();
     668                 : 
     669                 :   // Check for percentage based values and a containing block height that
     670                 :   // depends on the content height. Treat them like 'auto'
     671               0 :   if (NS_AUTOHEIGHT == aContainingBlockHeight) {
     672               0 :     if (mStylePosition->OffsetHasPercent(NS_SIDE_TOP)) {
     673               0 :       topIsAuto = true;
     674                 :     }
     675               0 :     if (mStylePosition->OffsetHasPercent(NS_SIDE_BOTTOM)) {
     676               0 :       bottomIsAuto = true;
     677                 :     }
     678                 :   }
     679                 : 
     680                 :   // If neither is 'auto', 'bottom' is ignored
     681               0 :   if (!topIsAuto && !bottomIsAuto) {
     682               0 :     bottomIsAuto = true;
     683                 :   }
     684                 : 
     685               0 :   if (topIsAuto) {
     686               0 :     if (bottomIsAuto) {
     687                 :       // If both are 'auto' (their initial values), the computed values are 0
     688               0 :       mComputedOffsets.top = mComputedOffsets.bottom = 0;
     689                 :     } else {
     690                 :       // 'Bottom' isn't 'auto' so compute its value
     691                 :       mComputedOffsets.bottom = nsLayoutUtils::
     692                 :         ComputeHeightDependentValue(aContainingBlockHeight,
     693               0 :                                     mStylePosition->mOffset.GetBottom());
     694                 :       
     695                 :       // Computed value for 'top' is minus the value of 'bottom'
     696               0 :       mComputedOffsets.top = -mComputedOffsets.bottom;
     697                 :     }
     698                 : 
     699                 :   } else {
     700               0 :     NS_ASSERTION(bottomIsAuto, "unexpected specified constraint");
     701                 :     
     702                 :     // 'Top' isn't 'auto' so compute its value
     703                 :     mComputedOffsets.top = nsLayoutUtils::
     704                 :       ComputeHeightDependentValue(aContainingBlockHeight,
     705               0 :                                   mStylePosition->mOffset.GetTop());
     706                 : 
     707                 :     // Computed value for 'bottom' is minus the value of 'top'
     708               0 :     mComputedOffsets.bottom = -mComputedOffsets.top;
     709                 :   }
     710                 : 
     711                 :   // Store the offset
     712               0 :   FrameProperties props(aPresContext->PropertyTable(), frame);
     713                 :   nsPoint* offsets = static_cast<nsPoint*>
     714               0 :     (props.Get(nsIFrame::ComputedOffsetProperty()));
     715               0 :   if (offsets) {
     716               0 :     offsets->MoveTo(mComputedOffsets.left, mComputedOffsets.top);
     717                 :   } else {
     718                 :     props.Set(nsIFrame::ComputedOffsetProperty(),
     719               0 :               new nsPoint(mComputedOffsets.left, mComputedOffsets.top));
     720                 :   }
     721               0 : }
     722                 : 
     723                 : nsIFrame*
     724               0 : nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame* aFrame,
     725                 :                                                nscoord& aCBLeftEdge,
     726                 :                                                nscoord& aCBWidth)
     727                 : {
     728               0 :   aFrame = aFrame->GetContainingBlock();
     729               0 :   NS_ASSERTION(aFrame != frame, "How did that happen?");
     730                 : 
     731                 :   /* Now aFrame is the containing block we want */
     732                 : 
     733                 :   /* Check whether the containing block is currently being reflowed.
     734                 :      If so, use the info from the reflow state. */
     735                 :   const nsHTMLReflowState* state;
     736               0 :   if (aFrame->GetStateBits() & NS_FRAME_IN_REFLOW) {
     737               0 :     for (state = parentReflowState; state && state->frame != aFrame;
     738                 :          state = state->parentReflowState) {
     739                 :       /* do nothing */
     740                 :     }
     741                 :   } else {
     742               0 :     state = nsnull;
     743                 :   }
     744                 :   
     745               0 :   if (state) {
     746               0 :     aCBLeftEdge = state->mComputedBorderPadding.left;
     747               0 :     aCBWidth = state->mComputedWidth;
     748                 :   } else {
     749                 :     /* Didn't find a reflow state for aFrame.  Just compute the information we
     750                 :        want, on the assumption that aFrame already knows its size.  This really
     751                 :        ought to be true by now. */
     752               0 :     NS_ASSERTION(!(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW),
     753                 :                  "aFrame shouldn't be in reflow; we'll lie if it is");
     754               0 :     nsMargin borderPadding = aFrame->GetUsedBorderAndPadding();
     755               0 :     aCBLeftEdge = borderPadding.left;
     756               0 :     aCBWidth = aFrame->GetSize().width - borderPadding.LeftRight();
     757                 :   }
     758                 : 
     759               0 :   return aFrame;
     760                 : }
     761                 : 
     762                 : // When determining the hypothetical box that would have been if the element
     763                 : // had been in the flow we may not be able to exactly determine both the left
     764                 : // and right edges. For example, if the element is a non-replaced inline-level
     765                 : // element we would have to reflow it in order to determine it desired width.
     766                 : // In that case depending on the progression direction either the left or
     767                 : // right edge would be marked as not being exact
     768                 : struct nsHypotheticalBox {
     769                 :   // offsets from left edge of containing block (which is a padding edge)
     770                 :   nscoord       mLeft, mRight;
     771                 :   // offset from top edge of containing block (which is a padding edge)
     772                 :   nscoord       mTop;
     773                 : #ifdef DEBUG
     774                 :   bool          mLeftIsExact, mRightIsExact;
     775                 : #endif
     776                 : 
     777               0 :   nsHypotheticalBox() {
     778                 : #ifdef DEBUG
     779               0 :     mLeftIsExact = mRightIsExact = false;
     780                 : #endif
     781               0 :   }
     782                 : };
     783                 :       
     784                 : static bool
     785               0 : GetIntrinsicSizeFor(nsIFrame* aFrame, nsSize& aIntrinsicSize, nsIAtom* aFrameType)
     786                 : {
     787                 :   // See if it is an image frame
     788               0 :   bool success = false;
     789                 : 
     790                 :   // Currently the only type of replaced frame that we can get the intrinsic
     791                 :   // size for is an image frame
     792                 :   // XXX We should add back the GetReflowMetrics() function and one of the
     793                 :   // things should be the intrinsic size...
     794               0 :   if (aFrameType == nsGkAtoms::imageFrame) {
     795               0 :     nsImageFrame* imageFrame = (nsImageFrame*)aFrame;
     796                 : 
     797               0 :     if (NS_SUCCEEDED(imageFrame->GetIntrinsicImageSize(aIntrinsicSize))) {
     798               0 :       success = (aIntrinsicSize != nsSize(0, 0));
     799                 :     }
     800                 :   }
     801               0 :   return success;
     802                 : }
     803                 : 
     804                 : /**
     805                 :  * aInsideBoxSizing returns the part of the horizontal padding, border,
     806                 :  * and margin that goes inside the edge given by -moz-box-sizing;
     807                 :  * aOutsideBoxSizing returns the rest.
     808                 :  */
     809                 : void
     810               0 : nsHTMLReflowState::CalculateHorizBorderPaddingMargin(
     811                 :                        nscoord aContainingBlockWidth,
     812                 :                        nscoord* aInsideBoxSizing,
     813                 :                        nscoord* aOutsideBoxSizing)
     814                 : {
     815               0 :   const nsMargin& border = mStyleBorder->GetActualBorder();
     816               0 :   nsMargin padding, margin;
     817                 : 
     818                 :   // See if the style system can provide us the padding directly
     819               0 :   if (!mStylePadding->GetPadding(padding)) {
     820                 :     // We have to compute the left and right values
     821                 :     padding.left = nsLayoutUtils::
     822                 :       ComputeWidthDependentValue(aContainingBlockWidth,
     823               0 :                                  mStylePadding->mPadding.GetLeft());
     824                 :     padding.right = nsLayoutUtils::
     825                 :       ComputeWidthDependentValue(aContainingBlockWidth,
     826               0 :                                  mStylePadding->mPadding.GetRight());
     827                 :   }
     828                 : 
     829                 :   // See if the style system can provide us the margin directly
     830               0 :   if (!mStyleMargin->GetMargin(margin)) {
     831                 :     // We have to compute the left and right values
     832               0 :     if (eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit()) {
     833                 :       // XXX FIXME (or does CalculateBlockSideMargins do this?)
     834               0 :       margin.left = 0;  // just ignore
     835                 :     } else {
     836                 :       margin.left = nsLayoutUtils::
     837                 :         ComputeWidthDependentValue(aContainingBlockWidth,
     838               0 :                                    mStyleMargin->mMargin.GetLeft());
     839                 :     }
     840               0 :     if (eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit()) {
     841                 :       // XXX FIXME (or does CalculateBlockSideMargins do this?)
     842               0 :       margin.right = 0;  // just ignore
     843                 :     } else {
     844                 :       margin.right = nsLayoutUtils::
     845                 :         ComputeWidthDependentValue(aContainingBlockWidth,
     846               0 :                                    mStyleMargin->mMargin.GetRight());
     847                 :     }
     848                 :   }
     849                 : 
     850                 :   nscoord outside =
     851               0 :     padding.LeftRight() + border.LeftRight() + margin.LeftRight();
     852               0 :   nscoord inside = 0;
     853               0 :   switch (mStylePosition->mBoxSizing) {
     854                 :     case NS_STYLE_BOX_SIZING_BORDER:
     855               0 :       inside += border.LeftRight();
     856                 :       // fall through
     857                 :     case NS_STYLE_BOX_SIZING_PADDING:
     858               0 :       inside += padding.LeftRight();
     859                 :   }
     860               0 :   outside -= inside;
     861               0 :   *aInsideBoxSizing = inside;
     862               0 :   *aOutsideBoxSizing = outside;
     863                 :   return;
     864                 : }
     865                 : 
     866                 : /**
     867                 :  * Returns true iff a pre-order traversal of the normal child
     868                 :  * frames rooted at aFrame finds no non-empty frame before aDescendant.
     869                 :  */
     870               0 : static bool AreAllEarlierInFlowFramesEmpty(nsIFrame* aFrame,
     871                 :   nsIFrame* aDescendant, bool* aFound) {
     872               0 :   if (aFrame == aDescendant) {
     873               0 :     *aFound = true;
     874               0 :     return true;
     875                 :   }
     876               0 :   if (!aFrame->IsSelfEmpty()) {
     877               0 :     *aFound = false;
     878               0 :     return false;
     879                 :   }
     880               0 :   for (nsIFrame* f = aFrame->GetFirstPrincipalChild(); f; f = f->GetNextSibling()) {
     881               0 :     bool allEmpty = AreAllEarlierInFlowFramesEmpty(f, aDescendant, aFound);
     882               0 :     if (*aFound || !allEmpty) {
     883               0 :       return allEmpty;
     884                 :     }
     885                 :   }
     886               0 :   *aFound = false;
     887               0 :   return true;
     888                 : }
     889                 : 
     890                 : // Calculate the hypothetical box that the element would have if it were in
     891                 : // the flow. The values returned are relative to the padding edge of the
     892                 : // absolute containing block
     893                 : // aContainingBlock is the placeholder's containing block (XXX rename it?)
     894                 : // cbrs->frame is the actual containing block
     895                 : void
     896               0 : nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext*    aPresContext,
     897                 :                                             nsIFrame*         aPlaceholderFrame,
     898                 :                                             nsIFrame*         aContainingBlock,
     899                 :                                             nscoord           aBlockLeftContentEdge,
     900                 :                                             nscoord           aBlockContentWidth,
     901                 :                                             const nsHTMLReflowState* cbrs,
     902                 :                                             nsHypotheticalBox& aHypotheticalBox,
     903                 :                                             nsIAtom*          aFrameType)
     904                 : {
     905               0 :   NS_ASSERTION(mStyleDisplay->mOriginalDisplay != NS_STYLE_DISPLAY_NONE,
     906                 :                "mOriginalDisplay has not been properly initialized");
     907                 :   
     908                 :   // If it's a replaced element and it has a 'auto' value for 'width', see if we
     909                 :   // can get the intrinsic size. This will allow us to exactly determine both the
     910                 :   // left and right edges
     911               0 :   bool isAutoWidth = mStylePosition->mWidth.GetUnit() == eStyleUnit_Auto;
     912               0 :   nsSize      intrinsicSize;
     913               0 :   bool        knowIntrinsicSize = false;
     914               0 :   if (NS_FRAME_IS_REPLACED(mFrameType) && isAutoWidth) {
     915                 :     // See if we can get the intrinsic size of the element
     916               0 :     knowIntrinsicSize = GetIntrinsicSizeFor(frame, intrinsicSize, aFrameType);
     917                 :   }
     918                 : 
     919                 :   // See if we can calculate what the box width would have been if the
     920                 :   // element had been in the flow
     921                 :   nscoord boxWidth;
     922               0 :   bool    knowBoxWidth = false;
     923               0 :   if ((NS_STYLE_DISPLAY_INLINE == mStyleDisplay->mOriginalDisplay) &&
     924               0 :       !NS_FRAME_IS_REPLACED(mFrameType)) {
     925                 :     // For non-replaced inline-level elements the 'width' property doesn't apply,
     926                 :     // so we don't know what the width would have been without reflowing it
     927                 : 
     928                 :   } else {
     929                 :     // It's either a replaced inline-level element or a block-level element
     930                 : 
     931                 :     // Determine the total amount of horizontal border/padding/margin that
     932                 :     // the element would have had if it had been in the flow. Note that we
     933                 :     // ignore any 'auto' and 'inherit' values
     934                 :     nscoord insideBoxSizing, outsideBoxSizing;
     935                 :     CalculateHorizBorderPaddingMargin(aBlockContentWidth,
     936               0 :                                       &insideBoxSizing, &outsideBoxSizing);
     937                 : 
     938               0 :     if (NS_FRAME_IS_REPLACED(mFrameType) && isAutoWidth) {
     939                 :       // It's a replaced element with an 'auto' width so the box width is
     940                 :       // its intrinsic size plus any border/padding/margin
     941               0 :       if (knowIntrinsicSize) {
     942               0 :         boxWidth = intrinsicSize.width + outsideBoxSizing + insideBoxSizing;
     943               0 :         knowBoxWidth = true;
     944                 :       }
     945                 : 
     946               0 :     } else if (isAutoWidth) {
     947                 :       // The box width is the containing block width
     948               0 :       boxWidth = aBlockContentWidth;
     949               0 :       knowBoxWidth = true;
     950                 :     
     951                 :     } else {
     952                 :       // We need to compute it. It's important we do this, because if it's
     953                 :       // percentage based this computed value may be different from the computed
     954                 :       // value calculated using the absolute containing block width
     955                 :       boxWidth = ComputeWidthValue(aBlockContentWidth,
     956                 :                                    insideBoxSizing, outsideBoxSizing,
     957               0 :                                    mStylePosition->mWidth) + 
     958               0 :                  insideBoxSizing + outsideBoxSizing;
     959               0 :       knowBoxWidth = true;
     960                 :     }
     961                 :   }
     962                 :   
     963                 :   // Get the 'direction' of the block
     964               0 :   const nsStyleVisibility* blockVis = aContainingBlock->GetStyleVisibility();
     965                 : 
     966                 :   // Get the placeholder x-offset and y-offset in the coordinate
     967                 :   // space of its containing block
     968                 :   // XXXbz the placeholder is not fully reflowed yet if our containing block is
     969                 :   // relatively positioned...
     970               0 :   nsPoint placeholderOffset = aPlaceholderFrame->GetOffsetTo(aContainingBlock);
     971                 : 
     972                 :   // First, determine the hypothetical box's mTop.  We want to check the
     973                 :   // content insertion frame of aContainingBlock for block-ness, but make
     974                 :   // sure to compute all coordinates in the coordinate system of
     975                 :   // aContainingBlock.
     976                 :   nsBlockFrame* blockFrame =
     977               0 :     nsLayoutUtils::GetAsBlock(aContainingBlock->GetContentInsertionFrame());
     978               0 :   if (blockFrame) {
     979               0 :     nscoord blockYOffset = blockFrame->GetOffsetTo(aContainingBlock).y;
     980                 :     bool isValid;
     981               0 :     nsBlockInFlowLineIterator iter(blockFrame, aPlaceholderFrame, &isValid);
     982               0 :     if (!isValid) {
     983                 :       // Give up.  We're probably dealing with somebody using
     984                 :       // position:absolute inside native-anonymous content anyway.
     985               0 :       aHypotheticalBox.mTop = placeholderOffset.y;
     986                 :     } else {
     987               0 :       NS_ASSERTION(iter.GetContainer() == blockFrame,
     988                 :                    "Found placeholder in wrong block!");
     989               0 :       nsBlockFrame::line_iterator lineBox = iter.GetLine();
     990                 : 
     991                 :       // How we determine the hypothetical box depends on whether the element
     992                 :       // would have been inline-level or block-level
     993               0 :       if (mStyleDisplay->IsOriginalDisplayInlineOutside()) {
     994                 :         // Use the top of the inline box which the placeholder lives in
     995                 :         // as the hypothetical box's top.
     996               0 :         aHypotheticalBox.mTop = lineBox->mBounds.y + blockYOffset;
     997                 :       } else {
     998                 :         // The element would have been block-level which means it would
     999                 :         // be below the line containing the placeholder frame, unless
    1000                 :         // all the frames before it are empty.  In that case, it would
    1001                 :         // have been just before this line.
    1002                 :         // XXXbz the line box is not fully reflowed yet if our
    1003                 :         // containing block is relatively positioned...
    1004               0 :         if (lineBox != iter.End()) {
    1005               0 :           nsIFrame * firstFrame = lineBox->mFirstChild;
    1006               0 :           bool found = false;
    1007               0 :           bool allEmpty = true;
    1008               0 :           while (firstFrame) { // See bug 223064
    1009                 :             allEmpty = AreAllEarlierInFlowFramesEmpty(firstFrame,
    1010               0 :               aPlaceholderFrame, &found);
    1011               0 :             if (found || !allEmpty)
    1012               0 :               break;
    1013               0 :             firstFrame = firstFrame->GetNextSibling();
    1014                 :           }
    1015               0 :           NS_ASSERTION(firstFrame, "Couldn't find placeholder!");
    1016                 : 
    1017               0 :           if (allEmpty) {
    1018                 :             // The top of the hypothetical box is the top of the line
    1019                 :             // containing the placeholder, since there is nothing in the
    1020                 :             // line before our placeholder except empty frames.
    1021               0 :             aHypotheticalBox.mTop = lineBox->mBounds.y + blockYOffset;
    1022                 :           } else {
    1023                 :             // The top of the hypothetical box is just below the line
    1024                 :             // containing the placeholder.
    1025               0 :             aHypotheticalBox.mTop = lineBox->mBounds.YMost() + blockYOffset;
    1026                 :           }
    1027                 :         } else {
    1028                 :           // Just use the placeholder's y-offset wrt the containing block
    1029               0 :           aHypotheticalBox.mTop = placeholderOffset.y;
    1030                 :         }
    1031                 :       }
    1032                 :     }
    1033                 :   } else {
    1034                 :     // The containing block is not a block, so it's probably something
    1035                 :     // like a XUL box, etc.
    1036                 :     // Just use the placeholder's y-offset
    1037               0 :     aHypotheticalBox.mTop = placeholderOffset.y;
    1038                 :   }
    1039                 : 
    1040                 :   // Second, determine the hypothetical box's mLeft & mRight
    1041                 :   // To determine the left and right offsets we need to look at the block's 'direction'
    1042               0 :   if (NS_STYLE_DIRECTION_LTR == blockVis->mDirection) {
    1043                 :     // How we determine the hypothetical box depends on whether the element
    1044                 :     // would have been inline-level or block-level
    1045               0 :     if (mStyleDisplay->IsOriginalDisplayInlineOutside()) {
    1046                 :       // The placeholder represents the left edge of the hypothetical box
    1047               0 :       aHypotheticalBox.mLeft = placeholderOffset.x;
    1048                 :     } else {
    1049               0 :       aHypotheticalBox.mLeft = aBlockLeftContentEdge;
    1050                 :     }
    1051                 : #ifdef DEBUG
    1052               0 :     aHypotheticalBox.mLeftIsExact = true;
    1053                 : #endif
    1054                 : 
    1055               0 :     if (knowBoxWidth) {
    1056               0 :       aHypotheticalBox.mRight = aHypotheticalBox.mLeft + boxWidth;
    1057                 : #ifdef DEBUG
    1058               0 :       aHypotheticalBox.mRightIsExact = true;
    1059                 : #endif
    1060                 :     } else {
    1061                 :       // We can't compute the right edge because we don't know the desired
    1062                 :       // width. So instead use the right content edge of the block parent,
    1063                 :       // but remember it's not exact
    1064               0 :       aHypotheticalBox.mRight = aBlockLeftContentEdge + aBlockContentWidth;
    1065                 : #ifdef DEBUG
    1066               0 :       aHypotheticalBox.mRightIsExact = false;
    1067                 : #endif
    1068                 :     }
    1069                 : 
    1070                 :   } else {
    1071                 :     // The placeholder represents the right edge of the hypothetical box
    1072               0 :     if (mStyleDisplay->IsOriginalDisplayInlineOutside()) {
    1073               0 :       aHypotheticalBox.mRight = placeholderOffset.x;
    1074                 :     } else {
    1075               0 :       aHypotheticalBox.mRight = aBlockLeftContentEdge + aBlockContentWidth;
    1076                 :     }
    1077                 : #ifdef DEBUG
    1078               0 :     aHypotheticalBox.mRightIsExact = true;
    1079                 : #endif
    1080                 :     
    1081               0 :     if (knowBoxWidth) {
    1082               0 :       aHypotheticalBox.mLeft = aHypotheticalBox.mRight - boxWidth;
    1083                 : #ifdef DEBUG
    1084               0 :       aHypotheticalBox.mLeftIsExact = true;
    1085                 : #endif
    1086                 :     } else {
    1087                 :       // We can't compute the left edge because we don't know the desired
    1088                 :       // width. So instead use the left content edge of the block parent,
    1089                 :       // but remember it's not exact
    1090               0 :       aHypotheticalBox.mLeft = aBlockLeftContentEdge;
    1091                 : #ifdef DEBUG
    1092               0 :       aHypotheticalBox.mLeftIsExact = false;
    1093                 : #endif
    1094                 :     }
    1095                 : 
    1096                 :   }
    1097                 : 
    1098                 :   // The current coordinate space is that of the nearest block to the placeholder.
    1099                 :   // Convert to the coordinate space of the absolute containing block
    1100                 :   // One weird thing here is that for fixed-positioned elements we want to do
    1101                 :   // the conversion incorrectly; specifically we want to ignore any scrolling
    1102                 :   // that may have happened;
    1103               0 :   nsPoint cbOffset;
    1104               0 :   if (mStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED &&
    1105                 :       // Exclude cases inside -moz-transform where fixed is like absolute.
    1106               0 :       nsLayoutUtils::IsReallyFixedPos(frame)) {
    1107                 :     // In this case, cbrs->frame will always be an ancestor of
    1108                 :     // aContainingBlock, so can just walk our way up the frame tree.
    1109                 :     // Make sure to not add positions of frames whose parent is a
    1110                 :     // scrollFrame, since we're doing fixed positioning, which assumes
    1111                 :     // everything is scrolled to (0,0).
    1112               0 :     cbOffset.MoveTo(0, 0);
    1113               0 :     do {
    1114               0 :       NS_ASSERTION(aContainingBlock,
    1115                 :                    "Should hit cbrs->frame before we run off the frame tree!");
    1116               0 :       cbOffset += aContainingBlock->GetPositionIgnoringScrolling();
    1117               0 :       aContainingBlock = aContainingBlock->GetParent();
    1118                 :     } while (aContainingBlock != cbrs->frame);
    1119                 :   } else {
    1120                 :     // XXXldb We need to either ignore scrolling for the absolute
    1121                 :     // positioning case too (and take the incompatibility) or figure out
    1122                 :     // how to make these positioned elements actually *move* when we
    1123                 :     // scroll, and thus avoid the resulting incremental reflow bugs.
    1124               0 :     cbOffset = aContainingBlock->GetOffsetTo(cbrs->frame);
    1125                 :   }
    1126               0 :   aHypotheticalBox.mLeft += cbOffset.x;
    1127               0 :   aHypotheticalBox.mTop += cbOffset.y;
    1128               0 :   aHypotheticalBox.mRight += cbOffset.x;
    1129                 :   
    1130                 :   // The specified offsets are relative to the absolute containing block's
    1131                 :   // padding edge and our current values are relative to the border edge, so
    1132                 :   // translate.
    1133               0 :   nsMargin border = cbrs->mComputedBorderPadding - cbrs->mComputedPadding;
    1134               0 :   aHypotheticalBox.mLeft -= border.left;
    1135               0 :   aHypotheticalBox.mRight -= border.left;
    1136               0 :   aHypotheticalBox.mTop -= border.top;
    1137               0 : }
    1138                 : 
    1139                 : void
    1140               0 : nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext* aPresContext,
    1141                 :                                            const nsHTMLReflowState* cbrs,
    1142                 :                                            nscoord containingBlockWidth,
    1143                 :                                            nscoord containingBlockHeight,
    1144                 :                                            nsIAtom* aFrameType)
    1145                 : {
    1146               0 :   NS_PRECONDITION(containingBlockHeight != NS_AUTOHEIGHT,
    1147                 :                   "containing block height must be constrained");
    1148                 : 
    1149               0 :   NS_ASSERTION(aFrameType != nsGkAtoms::tableFrame,
    1150                 :                "InitAbsoluteConstraints should not be called on table frames");
    1151               0 :   NS_ASSERTION(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
    1152                 :                "Why are we here?");
    1153                 : 
    1154                 :   // Get the placeholder frame
    1155                 :   nsIFrame*     placeholderFrame;
    1156                 : 
    1157               0 :   placeholderFrame = aPresContext->PresShell()->GetPlaceholderFrameFor(frame);
    1158               0 :   NS_ASSERTION(nsnull != placeholderFrame, "no placeholder frame");
    1159                 : 
    1160                 :   // If both 'left' and 'right' are 'auto' or both 'top' and 'bottom' are
    1161                 :   // 'auto', then compute the hypothetical box of where the element would
    1162                 :   // have been if it had been in the flow
    1163               0 :   nsHypotheticalBox hypotheticalBox;
    1164               0 :   if (((eStyleUnit_Auto == mStylePosition->mOffset.GetLeftUnit()) &&
    1165               0 :        (eStyleUnit_Auto == mStylePosition->mOffset.GetRightUnit())) ||
    1166               0 :       ((eStyleUnit_Auto == mStylePosition->mOffset.GetTopUnit()) &&
    1167               0 :        (eStyleUnit_Auto == mStylePosition->mOffset.GetBottomUnit()))) {
    1168                 :     // Find the nearest containing block frame to the placeholder frame,
    1169                 :     // and return its left edge and width.
    1170                 :     nscoord cbLeftEdge, cbWidth;
    1171                 :     nsIFrame* cbFrame = GetHypotheticalBoxContainer(placeholderFrame,
    1172                 :                                                     cbLeftEdge,
    1173               0 :                                                     cbWidth);
    1174                 : 
    1175                 :     CalculateHypotheticalBox(aPresContext, placeholderFrame, cbFrame,
    1176               0 :                              cbLeftEdge, cbWidth, cbrs, hypotheticalBox, aFrameType);
    1177                 :   }
    1178                 : 
    1179                 :   // Initialize the 'left' and 'right' computed offsets
    1180                 :   // XXX Handle new 'static-position' value...
    1181               0 :   bool          leftIsAuto = false, rightIsAuto = false;
    1182               0 :   if (eStyleUnit_Auto == mStylePosition->mOffset.GetLeftUnit()) {
    1183               0 :     mComputedOffsets.left = 0;
    1184               0 :     leftIsAuto = true;
    1185                 :   } else {
    1186                 :     mComputedOffsets.left = nsLayoutUtils::
    1187                 :       ComputeWidthDependentValue(containingBlockWidth,
    1188               0 :                                  mStylePosition->mOffset.GetLeft());
    1189                 :   }
    1190               0 :   if (eStyleUnit_Auto == mStylePosition->mOffset.GetRightUnit()) {
    1191               0 :     mComputedOffsets.right = 0;
    1192               0 :     rightIsAuto = true;
    1193                 :   } else {
    1194                 :     mComputedOffsets.right = nsLayoutUtils::
    1195                 :       ComputeWidthDependentValue(containingBlockWidth,
    1196               0 :                                  mStylePosition->mOffset.GetRight());
    1197                 :   }
    1198                 : 
    1199                 :   // Use the horizontal component of the hypothetical box in the cases
    1200                 :   // where it's needed.
    1201               0 :   if (leftIsAuto && rightIsAuto) {
    1202                 :     // Use the direction of the original ("static-position") containing block
    1203                 :     // to dictate whether 'left' or 'right' is treated like 'static-position'.
    1204               0 :     if (NS_STYLE_DIRECTION_LTR == placeholderFrame->GetContainingBlock()
    1205               0 :                                     ->GetStyleVisibility()->mDirection) {
    1206               0 :       NS_ASSERTION(hypotheticalBox.mLeftIsExact, "should always have "
    1207                 :                    "exact value on containing block's start side");
    1208               0 :       mComputedOffsets.left = hypotheticalBox.mLeft;
    1209               0 :       leftIsAuto = false;
    1210                 :     } else {
    1211               0 :       NS_ASSERTION(hypotheticalBox.mRightIsExact, "should always have "
    1212                 :                    "exact value on containing block's start side");
    1213               0 :       mComputedOffsets.right = containingBlockWidth - hypotheticalBox.mRight;
    1214               0 :       rightIsAuto = false;
    1215                 :     }
    1216                 :   }
    1217                 : 
    1218                 :   // Initialize the 'top' and 'bottom' computed offsets
    1219               0 :   bool        topIsAuto = false, bottomIsAuto = false;
    1220               0 :   if (eStyleUnit_Auto == mStylePosition->mOffset.GetTopUnit()) {
    1221               0 :     mComputedOffsets.top = 0;
    1222               0 :     topIsAuto = true;
    1223                 :   } else {
    1224                 :     mComputedOffsets.top = nsLayoutUtils::
    1225                 :       ComputeHeightDependentValue(containingBlockHeight,
    1226               0 :                                   mStylePosition->mOffset.GetTop());
    1227                 :   }
    1228               0 :   if (eStyleUnit_Auto == mStylePosition->mOffset.GetBottomUnit()) {
    1229               0 :     mComputedOffsets.bottom = 0;        
    1230               0 :     bottomIsAuto = true;
    1231                 :   } else {
    1232                 :     mComputedOffsets.bottom = nsLayoutUtils::
    1233                 :       ComputeHeightDependentValue(containingBlockHeight,
    1234               0 :                                   mStylePosition->mOffset.GetBottom());
    1235                 :   }
    1236                 : 
    1237               0 :   if (topIsAuto && bottomIsAuto) {
    1238                 :     // Treat 'top' like 'static-position'
    1239               0 :     mComputedOffsets.top = hypotheticalBox.mTop;
    1240               0 :     topIsAuto = false;
    1241                 :   }
    1242                 : 
    1243               0 :   bool widthIsAuto = eStyleUnit_Auto == mStylePosition->mWidth.GetUnit();
    1244               0 :   bool heightIsAuto = eStyleUnit_Auto == mStylePosition->mHeight.GetUnit();
    1245                 : 
    1246               0 :   bool shrinkWrap = leftIsAuto || rightIsAuto;
    1247                 :   {
    1248               0 :     AutoMaybeNullInflationContainer an(frame);
    1249                 : 
    1250                 :     nsSize size =
    1251                 :       frame->ComputeSize(rendContext,
    1252                 :                          nsSize(containingBlockWidth,
    1253                 :                                 containingBlockHeight),
    1254                 :                          containingBlockWidth, // XXX or availableWidth?
    1255               0 :                          nsSize(mComputedMargin.LeftRight() +
    1256               0 :                                   mComputedOffsets.LeftRight(),
    1257               0 :                                 mComputedMargin.TopBottom() +
    1258               0 :                                   mComputedOffsets.TopBottom()),
    1259               0 :                          nsSize(mComputedBorderPadding.LeftRight() -
    1260               0 :                                   mComputedPadding.LeftRight(),
    1261               0 :                                 mComputedBorderPadding.TopBottom() -
    1262               0 :                                   mComputedPadding.TopBottom()),
    1263                 :                          nsSize(mComputedPadding.LeftRight(),
    1264                 :                                 mComputedPadding.TopBottom()),
    1265               0 :                          shrinkWrap);
    1266               0 :     mComputedWidth = size.width;
    1267               0 :     mComputedHeight = size.height;
    1268                 :   }
    1269               0 :   NS_ASSERTION(mComputedWidth >= 0, "Bogus width");
    1270               0 :   NS_ASSERTION(mComputedHeight == NS_UNCONSTRAINEDSIZE ||
    1271                 :                mComputedHeight >= 0, "Bogus height");
    1272                 : 
    1273                 :   // XXX Now that we have ComputeSize, can we condense many of the
    1274                 :   // branches off of widthIsAuto?
    1275                 : 
    1276               0 :   if (leftIsAuto) {
    1277                 :     // We know 'right' is not 'auto' anymore thanks to the hypothetical
    1278                 :     // box code above.
    1279                 :     // Solve for 'left'.
    1280               0 :     if (widthIsAuto) {
    1281                 :       // XXXldb This, and the corresponding code in
    1282                 :       // nsAbsoluteContainingBlock.cpp, could probably go away now that
    1283                 :       // we always compute widths.
    1284               0 :       mComputedOffsets.left = NS_AUTOOFFSET;
    1285                 :     } else {
    1286                 :       mComputedOffsets.left = containingBlockWidth - mComputedMargin.left -
    1287                 :         mComputedBorderPadding.left - mComputedWidth - mComputedBorderPadding.right - 
    1288               0 :         mComputedMargin.right - mComputedOffsets.right;
    1289                 : 
    1290                 :     }
    1291               0 :   } else if (rightIsAuto) {
    1292                 :     // We know 'left' is not 'auto' anymore thanks to the hypothetical
    1293                 :     // box code above.
    1294                 :     // Solve for 'right'.
    1295               0 :     if (widthIsAuto) {
    1296                 :       // XXXldb This, and the corresponding code in
    1297                 :       // nsAbsoluteContainingBlock.cpp, could probably go away now that
    1298                 :       // we always compute widths.
    1299               0 :       mComputedOffsets.right = NS_AUTOOFFSET;
    1300                 :     } else {
    1301                 :       mComputedOffsets.right = containingBlockWidth - mComputedOffsets.left -
    1302                 :         mComputedMargin.left - mComputedBorderPadding.left - mComputedWidth -
    1303               0 :         mComputedBorderPadding.right - mComputedMargin.right;
    1304                 :     }
    1305                 :   } else {
    1306                 :     // Neither 'left' nor 'right' is 'auto'.  However, the width might
    1307                 :     // still not fill all the available space (even though we didn't
    1308                 :     // shrink-wrap) in case:
    1309                 :     //  * width was specified
    1310                 :     //  * we're dealing with a replaced element
    1311                 :     //  * width was constrained by min-width or max-width.
    1312                 : 
    1313                 :     nscoord availMarginSpace = containingBlockWidth -
    1314               0 :                                mComputedOffsets.LeftRight() -
    1315               0 :                                mComputedMargin.LeftRight() -
    1316               0 :                                mComputedBorderPadding.LeftRight() -
    1317               0 :                                mComputedWidth;
    1318                 :     bool marginLeftIsAuto =
    1319               0 :       eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit();
    1320                 :     bool marginRightIsAuto =
    1321               0 :       eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit();
    1322                 : 
    1323               0 :     if (marginLeftIsAuto) {
    1324               0 :       if (marginRightIsAuto) {
    1325               0 :         if (availMarginSpace < 0) {
    1326                 :           // Note that this case is different from the neither-'auto'
    1327                 :           // case below, where the spec says to ignore 'left'/'right'.
    1328               0 :           if (cbrs &&
    1329                 :               NS_STYLE_DIRECTION_RTL == cbrs->mStyleVisibility->mDirection) {
    1330                 :             // Ignore the specified value for 'margin-left'.
    1331               0 :             mComputedMargin.left = availMarginSpace;
    1332                 :           } else {
    1333                 :             // Ignore the specified value for 'margin-right'.
    1334               0 :             mComputedMargin.right = availMarginSpace;
    1335                 :           }
    1336                 :         } else {
    1337                 :           // Both 'margin-left' and 'margin-right' are 'auto', so they get
    1338                 :           // equal values
    1339               0 :           mComputedMargin.left = availMarginSpace / 2;
    1340               0 :           mComputedMargin.right = availMarginSpace - mComputedMargin.left;
    1341                 :         }
    1342                 :       } else {
    1343                 :         // Just 'margin-left' is 'auto'
    1344               0 :         mComputedMargin.left = availMarginSpace;
    1345                 :       }
    1346                 :     } else {
    1347               0 :       if (marginRightIsAuto) {
    1348                 :         // Just 'margin-right' is 'auto'
    1349               0 :         mComputedMargin.right = availMarginSpace;
    1350                 :       } else {
    1351                 :         // We're over-constrained so use the direction of the containing
    1352                 :         // block to dictate which value to ignore.  (And note that the
    1353                 :         // spec says to ignore 'left' or 'right' rather than
    1354                 :         // 'margin-left' or 'margin-right'.)
    1355                 :         // Note that this case is different from the both-'auto' case
    1356                 :         // above, where the spec says to ignore
    1357                 :         // 'margin-left'/'margin-right'.
    1358               0 :         if (cbrs &&
    1359                 :             NS_STYLE_DIRECTION_RTL == cbrs->mStyleVisibility->mDirection) {
    1360                 :           // Ignore the specified value for 'left'.
    1361               0 :           mComputedOffsets.left += availMarginSpace;
    1362                 :         } else {
    1363                 :           // Ignore the specified value for 'right'.
    1364               0 :           mComputedOffsets.right += availMarginSpace;
    1365                 :         }
    1366                 :       }
    1367                 :     }
    1368                 :   }
    1369                 : 
    1370               0 :   if (topIsAuto) {
    1371                 :     // solve for 'top'
    1372               0 :     if (heightIsAuto) {
    1373               0 :       mComputedOffsets.top = NS_AUTOOFFSET;
    1374                 :     } else {
    1375                 :       mComputedOffsets.top = containingBlockHeight - mComputedMargin.top -
    1376                 :         mComputedBorderPadding.top - mComputedHeight - mComputedBorderPadding.bottom - 
    1377               0 :         mComputedMargin.bottom - mComputedOffsets.bottom;
    1378                 :     }
    1379               0 :   } else if (bottomIsAuto) {
    1380                 :     // solve for 'bottom'
    1381               0 :     if (heightIsAuto) {
    1382               0 :       mComputedOffsets.bottom = NS_AUTOOFFSET;
    1383                 :     } else {
    1384                 :       mComputedOffsets.bottom = containingBlockHeight - mComputedOffsets.top -
    1385                 :         mComputedMargin.top - mComputedBorderPadding.top - mComputedHeight -
    1386               0 :         mComputedBorderPadding.bottom - mComputedMargin.bottom;
    1387                 :     }
    1388                 :   } else {
    1389                 :     // Neither 'top' nor 'bottom' is 'auto'.
    1390                 :     nscoord autoHeight = containingBlockHeight -
    1391               0 :                          mComputedOffsets.TopBottom() -
    1392               0 :                          mComputedMargin.TopBottom() -
    1393               0 :                          mComputedBorderPadding.TopBottom();
    1394               0 :     if (autoHeight < 0) {
    1395               0 :       autoHeight = 0;
    1396                 :     }
    1397                 : 
    1398               0 :     if (mComputedHeight == NS_UNCONSTRAINEDSIZE) {
    1399                 :       // For non-replaced elements with 'height' auto, the 'height'
    1400                 :       // fills the remaining space.
    1401               0 :       mComputedHeight = autoHeight;
    1402                 : 
    1403                 :       // XXX Do these need box-sizing adjustments?
    1404               0 :       if (mComputedHeight > mComputedMaxHeight)
    1405               0 :         mComputedHeight = mComputedMaxHeight;
    1406               0 :       if (mComputedHeight < mComputedMinHeight)
    1407               0 :         mComputedHeight = mComputedMinHeight;
    1408                 :     }
    1409                 : 
    1410                 :     // The height might still not fill all the available space in case:
    1411                 :     //  * height was specified
    1412                 :     //  * we're dealing with a replaced element
    1413                 :     //  * height was constrained by min-height or max-height.
    1414               0 :     nscoord availMarginSpace = autoHeight - mComputedHeight;
    1415                 :     bool marginTopIsAuto =
    1416               0 :       eStyleUnit_Auto == mStyleMargin->mMargin.GetTopUnit();
    1417                 :     bool marginBottomIsAuto =
    1418               0 :       eStyleUnit_Auto == mStyleMargin->mMargin.GetBottomUnit();
    1419                 : 
    1420               0 :     if (marginTopIsAuto) {
    1421               0 :       if (marginBottomIsAuto) {
    1422               0 :         if (availMarginSpace < 0) {
    1423                 :           // FIXME: Note that the spec doesn't actually say we should do this!
    1424               0 :           mComputedMargin.bottom = availMarginSpace;
    1425                 :         } else {
    1426                 :           // Both 'margin-top' and 'margin-bottom' are 'auto', so they get
    1427                 :           // equal values
    1428               0 :           mComputedMargin.top = availMarginSpace / 2;
    1429               0 :           mComputedMargin.bottom = availMarginSpace - mComputedMargin.top;
    1430                 :         }
    1431                 :       } else {
    1432                 :         // Just 'margin-top' is 'auto'
    1433               0 :         mComputedMargin.top = availMarginSpace;
    1434                 :       }
    1435                 :     } else {
    1436               0 :       if (marginBottomIsAuto) {
    1437                 :         // Just 'margin-bottom' is 'auto'
    1438               0 :         mComputedMargin.bottom = availMarginSpace;
    1439                 :       } else {
    1440                 :         // We're over-constrained so ignore the specified value for
    1441                 :         // 'bottom'.  (And note that the spec says to ignore 'bottom'
    1442                 :         // rather than 'margin-bottom'.)
    1443               0 :         mComputedOffsets.bottom += availMarginSpace;
    1444                 :       }
    1445                 :     }
    1446                 :   }
    1447               0 : }
    1448                 : 
    1449                 : nscoord 
    1450               0 : GetVerticalMarginBorderPadding(const nsHTMLReflowState* aReflowState)
    1451                 : {
    1452               0 :   nscoord result = 0;
    1453               0 :   if (!aReflowState) return result;
    1454                 : 
    1455                 :   // zero auto margins
    1456               0 :   nsMargin margin = aReflowState->mComputedMargin;
    1457               0 :   if (NS_AUTOMARGIN == margin.top) 
    1458               0 :     margin.top = 0;
    1459               0 :   if (NS_AUTOMARGIN == margin.bottom) 
    1460               0 :     margin.bottom = 0;
    1461                 : 
    1462               0 :   result += margin.top + margin.bottom;
    1463                 :   result += aReflowState->mComputedBorderPadding.top + 
    1464               0 :             aReflowState->mComputedBorderPadding.bottom;
    1465                 : 
    1466               0 :   return result;
    1467                 : }
    1468                 : 
    1469                 : /* Get the height based on the viewport of the containing block specified 
    1470                 :  * in aReflowState when the containing block has mComputedHeight == NS_AUTOHEIGHT
    1471                 :  * This will walk up the chain of containing blocks looking for a computed height
    1472                 :  * until it finds the canvas frame, or it encounters a frame that is not a block,
    1473                 :  * area, or scroll frame. This handles compatibility with IE (see bug 85016 and bug 219693)
    1474                 :  *
    1475                 :  *  When we encounter scrolledContent block frames, we skip over them, since they are guaranteed to not be useful for computing the containing block.
    1476                 :  *
    1477                 :  * See also IsQuirkContainingBlockHeight.
    1478                 :  */
    1479                 : static nscoord
    1480               0 : CalcQuirkContainingBlockHeight(const nsHTMLReflowState* aCBReflowState)
    1481                 : {
    1482               0 :   nsHTMLReflowState* firstAncestorRS = nsnull; // a candidate for html frame
    1483               0 :   nsHTMLReflowState* secondAncestorRS = nsnull; // a candidate for body frame
    1484                 :   
    1485                 :   // initialize the default to NS_AUTOHEIGHT as this is the containings block
    1486                 :   // computed height when this function is called. It is possible that we 
    1487                 :   // don't alter this height especially if we are restricted to one level
    1488               0 :   nscoord result = NS_AUTOHEIGHT; 
    1489                 :                              
    1490               0 :   const nsHTMLReflowState* rs = aCBReflowState;
    1491               0 :   for (; rs; rs = (nsHTMLReflowState *)(rs->parentReflowState)) { 
    1492               0 :     nsIAtom* frameType = rs->frame->GetType();
    1493                 :     // if the ancestor is auto height then skip it and continue up if it 
    1494                 :     // is the first block frame and possibly the body/html
    1495               0 :     if (nsGkAtoms::blockFrame == frameType ||
    1496                 : #ifdef MOZ_XUL
    1497                 :         nsGkAtoms::XULLabelFrame == frameType ||
    1498                 : #endif
    1499                 :         nsGkAtoms::scrollFrame == frameType) {
    1500                 : 
    1501               0 :       secondAncestorRS = firstAncestorRS;
    1502               0 :       firstAncestorRS = (nsHTMLReflowState*)rs;
    1503                 : 
    1504                 :       // If the current frame we're looking at is positioned, we don't want to
    1505                 :       // go any further (see bug 221784).  The behavior we want here is: 1) If
    1506                 :       // not auto-height, use this as the percentage base.  2) If auto-height,
    1507                 :       // keep looking, unless the frame is positioned.
    1508               0 :       if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
    1509               0 :         if (rs->frame->GetStyleDisplay()->IsAbsolutelyPositioned()) {
    1510               0 :           break;
    1511                 :         } else {
    1512               0 :           continue;
    1513                 :         }
    1514                 :       }
    1515                 :     }
    1516               0 :     else if (nsGkAtoms::canvasFrame == frameType) {
    1517                 :       // Always continue on to the height calculation
    1518                 :     }
    1519               0 :     else if (nsGkAtoms::pageContentFrame == frameType) {
    1520               0 :       nsIFrame* prevInFlow = rs->frame->GetPrevInFlow();
    1521                 :       // only use the page content frame for a height basis if it is the first in flow
    1522               0 :       if (prevInFlow) 
    1523               0 :         break;
    1524                 :     }
    1525                 :     else {
    1526               0 :       break;
    1527                 :     }
    1528                 : 
    1529                 :     // if the ancestor is the page content frame then the percent base is 
    1530                 :     // the avail height, otherwise it is the computed height
    1531                 :     result = (nsGkAtoms::pageContentFrame == frameType)
    1532               0 :              ? rs->availableHeight : rs->ComputedHeight();
    1533                 :     // if unconstrained - don't sutract borders - would result in huge height
    1534               0 :     if (NS_AUTOHEIGHT == result) return result;
    1535                 : 
    1536                 :     // if we got to the canvas or page content frame, then subtract out 
    1537                 :     // margin/border/padding for the BODY and HTML elements
    1538               0 :     if ((nsGkAtoms::canvasFrame == frameType) || 
    1539                 :         (nsGkAtoms::pageContentFrame == frameType)) {
    1540                 : 
    1541               0 :       result -= GetVerticalMarginBorderPadding(firstAncestorRS); 
    1542               0 :       result -= GetVerticalMarginBorderPadding(secondAncestorRS); 
    1543                 : 
    1544                 : #ifdef DEBUG
    1545                 :       // make sure the first ancestor is the HTML and the second is the BODY
    1546               0 :       if (firstAncestorRS) {
    1547               0 :         nsIContent* frameContent = firstAncestorRS->frame->GetContent();
    1548               0 :         if (frameContent) {
    1549               0 :           nsIAtom *contentTag = frameContent->Tag();
    1550               0 :           NS_ASSERTION(contentTag == nsGkAtoms::html, "First ancestor is not HTML");
    1551                 :         }
    1552                 :       }
    1553               0 :       if (secondAncestorRS) {
    1554               0 :         nsIContent* frameContent = secondAncestorRS->frame->GetContent();
    1555               0 :         if (frameContent) {
    1556               0 :           nsIAtom *contentTag = frameContent->Tag();
    1557               0 :           NS_ASSERTION(contentTag == nsGkAtoms::body, "Second ancestor is not BODY");
    1558                 :         }
    1559               0 :       }
    1560                 : #endif
    1561                 :       
    1562                 :     }
    1563                 :     // if we got to the html frame (a block child of the canvas) ...
    1564               0 :     else if (nsGkAtoms::blockFrame == frameType &&
    1565                 :              rs->parentReflowState &&
    1566                 :              nsGkAtoms::canvasFrame ==
    1567               0 :                rs->parentReflowState->frame->GetType()) {
    1568                 :       // ... then subtract out margin/border/padding for the BODY element
    1569               0 :       result -= GetVerticalMarginBorderPadding(secondAncestorRS);
    1570                 :     }
    1571               0 :     break;
    1572                 :   }
    1573                 : 
    1574                 :   // Make sure not to return a negative height here!
    1575               0 :   return NS_MAX(result, 0);
    1576                 : }
    1577                 : // Called by InitConstraints() to compute the containing block rectangle for
    1578                 : // the element. Handles the special logic for absolutely positioned elements
    1579                 : void
    1580               0 : nsHTMLReflowState::ComputeContainingBlockRectangle(nsPresContext*          aPresContext,
    1581                 :                                                    const nsHTMLReflowState* aContainingBlockRS,
    1582                 :                                                    nscoord&                 aContainingBlockWidth,
    1583                 :                                                    nscoord&                 aContainingBlockHeight)
    1584                 : {
    1585                 :   // Unless the element is absolutely positioned, the containing block is
    1586                 :   // formed by the content edge of the nearest block-level ancestor
    1587               0 :   aContainingBlockWidth = aContainingBlockRS->mComputedWidth;
    1588               0 :   aContainingBlockHeight = aContainingBlockRS->mComputedHeight;
    1589                 : 
    1590                 :   // mFrameType for abs-pos tables is NS_CSS_FRAME_TYPE_BLOCK, so we need to
    1591                 :   // special case them here.
    1592               0 :   if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE ||
    1593               0 :       (frame->GetType() == nsGkAtoms::tableFrame &&
    1594               0 :        frame->GetStyleDisplay()->IsAbsolutelyPositioned() &&
    1595               0 :        (frame->GetParent()->GetStateBits() & NS_FRAME_OUT_OF_FLOW))) {
    1596                 :     // See if the ancestor is block-level or inline-level
    1597               0 :     if (NS_FRAME_GET_TYPE(aContainingBlockRS->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) {
    1598                 :       // Base our size on the actual size of the frame.  In cases when this is
    1599                 :       // completely bogus (eg initial reflow), this code shouldn't even be
    1600                 :       // called, since the code in nsInlineFrame::Reflow will pass in
    1601                 :       // the containing block dimensions to our constructor.
    1602                 :       // XXXbz we should be taking the in-flows into account too, but
    1603                 :       // that's very hard.
    1604                 :       nsMargin computedBorder = aContainingBlockRS->mComputedBorderPadding -
    1605               0 :         aContainingBlockRS->mComputedPadding;
    1606               0 :       aContainingBlockWidth = aContainingBlockRS->frame->GetRect().width -
    1607               0 :         computedBorder.LeftRight();;
    1608               0 :       NS_ASSERTION(aContainingBlockWidth >= 0,
    1609                 :                    "Negative containing block width!");
    1610               0 :       aContainingBlockHeight = aContainingBlockRS->frame->GetRect().height -
    1611               0 :         computedBorder.TopBottom();
    1612               0 :       NS_ASSERTION(aContainingBlockHeight >= 0,
    1613                 :                    "Negative containing block height!");
    1614                 :     } else {
    1615                 :       // If the ancestor is block-level, the containing block is formed by the
    1616                 :       // padding edge of the ancestor
    1617               0 :       aContainingBlockWidth += aContainingBlockRS->mComputedPadding.LeftRight();
    1618               0 :       aContainingBlockHeight += aContainingBlockRS->mComputedPadding.TopBottom();
    1619                 :     }
    1620                 :   } else {
    1621                 :     // an element in quirks mode gets a containing block based on looking for a
    1622                 :     // parent with a non-auto height if the element has a percent height
    1623                 :     // Note: We don't emulate this quirk for percents in calc().
    1624               0 :     if (NS_AUTOHEIGHT == aContainingBlockHeight) {
    1625               0 :       if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
    1626               0 :           mStylePosition->mHeight.GetUnit() == eStyleUnit_Percent) {
    1627               0 :         aContainingBlockHeight = CalcQuirkContainingBlockHeight(aContainingBlockRS);
    1628                 :       }
    1629                 :     }
    1630                 :   }
    1631               0 : }
    1632                 : 
    1633                 : // Prefs callback to pick up changes
    1634                 : static int
    1635               0 : PrefsChanged(const char *aPrefName, void *instance)
    1636                 : {
    1637                 :   sBlinkIsAllowed =
    1638               0 :     Preferences::GetBool("browser.blink_allowed", sBlinkIsAllowed);
    1639                 : 
    1640               0 :   return 0; /* PREF_OK */
    1641                 : }
    1642                 : 
    1643                 : // Check to see if |text-decoration: blink| is allowed.  The first time
    1644                 : // called, register the callback and then force-load the pref.  After that,
    1645                 : // just use the cached value.
    1646               0 : static bool BlinkIsAllowed(void)
    1647                 : {
    1648               0 :   if (!sPrefIsLoaded) {
    1649                 :     // Set up a listener and check the initial value
    1650               0 :     Preferences::RegisterCallback(PrefsChanged, "browser.blink_allowed");
    1651               0 :     PrefsChanged(nsnull, nsnull);
    1652               0 :     sPrefIsLoaded = true;
    1653                 :   }
    1654               0 :   return sBlinkIsAllowed;
    1655                 : }
    1656                 : 
    1657               0 : static eNormalLineHeightControl GetNormalLineHeightCalcControl(void)
    1658                 : {
    1659               0 :   if (sNormalLineHeightControl == eUninitialized) {
    1660                 :     // browser.display.normal_lineheight_calc_control is not user
    1661                 :     // changeable, so no need to register callback for it.
    1662                 :     PRInt32 val =
    1663                 :       Preferences::GetInt("browser.display.normal_lineheight_calc_control",
    1664               0 :                           eNoExternalLeading);
    1665               0 :     sNormalLineHeightControl = static_cast<eNormalLineHeightControl>(val);
    1666                 :   }
    1667               0 :   return sNormalLineHeightControl;
    1668                 : }
    1669                 : 
    1670                 : static inline bool
    1671               0 : IsSideCaption(nsIFrame* aFrame, const nsStyleDisplay* aStyleDisplay)
    1672                 : {
    1673               0 :   if (aStyleDisplay->mDisplay != NS_STYLE_DISPLAY_TABLE_CAPTION)
    1674               0 :     return false;
    1675               0 :   PRUint8 captionSide = aFrame->GetStyleTableBorder()->mCaptionSide;
    1676                 :   return captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
    1677               0 :          captionSide == NS_STYLE_CAPTION_SIDE_RIGHT;
    1678                 : }
    1679                 : 
    1680                 : // XXX refactor this code to have methods for each set of properties
    1681                 : // we are computing: width,height,line-height; margin; offsets
    1682                 : 
    1683                 : void
    1684               0 : nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext,
    1685                 :                                    nscoord         aContainingBlockWidth,
    1686                 :                                    nscoord         aContainingBlockHeight,
    1687                 :                                    const nsMargin* aBorder,
    1688                 :                                    const nsMargin* aPadding,
    1689                 :                                    nsIAtom* aFrameType)
    1690                 : {
    1691               0 :   DISPLAY_INIT_CONSTRAINTS(frame, this,
    1692                 :                            aContainingBlockWidth, aContainingBlockHeight,
    1693                 :                            aBorder, aPadding);
    1694                 : 
    1695                 :   // If this is the root frame, then set the computed width and
    1696                 :   // height equal to the available space
    1697               0 :   if (nsnull == parentReflowState) {
    1698                 :     // XXXldb This doesn't mean what it used to!
    1699               0 :     InitOffsets(aContainingBlockWidth, aFrameType, aBorder, aPadding);
    1700                 :     // Override mComputedMargin since reflow roots start from the
    1701                 :     // frame's boundary, which is inside the margin.
    1702               0 :     mComputedMargin.SizeTo(0, 0, 0, 0);
    1703               0 :     mComputedOffsets.SizeTo(0, 0, 0, 0);
    1704                 : 
    1705               0 :     mComputedWidth = availableWidth - mComputedBorderPadding.LeftRight();
    1706               0 :     if (mComputedWidth < 0)
    1707               0 :       mComputedWidth = 0;
    1708               0 :     if (availableHeight != NS_UNCONSTRAINEDSIZE) {
    1709               0 :       mComputedHeight = availableHeight - mComputedBorderPadding.TopBottom();
    1710               0 :       if (mComputedHeight < 0)
    1711               0 :         mComputedHeight = 0;
    1712                 :     } else {
    1713               0 :       mComputedHeight = NS_UNCONSTRAINEDSIZE;
    1714                 :     }
    1715                 : 
    1716               0 :     mComputedMinWidth = mComputedMinHeight = 0;
    1717               0 :     mComputedMaxWidth = mComputedMaxHeight = NS_UNCONSTRAINEDSIZE;
    1718                 :   } else {
    1719                 :     // Get the containing block reflow state
    1720               0 :     const nsHTMLReflowState* cbrs = mCBReflowState;
    1721               0 :     NS_ASSERTION(nsnull != cbrs, "no containing block");
    1722                 : 
    1723                 :     // If we weren't given a containing block width and height, then
    1724                 :     // compute one
    1725               0 :     if (aContainingBlockWidth == -1) {
    1726                 :       ComputeContainingBlockRectangle(aPresContext, cbrs, aContainingBlockWidth, 
    1727               0 :                                       aContainingBlockHeight);
    1728                 :     }
    1729                 : 
    1730                 :     // See if the containing block height is based on the size of its
    1731                 :     // content
    1732                 :     nsIAtom* fType;
    1733               0 :     if (NS_AUTOHEIGHT == aContainingBlockHeight) {
    1734                 :       // See if the containing block is a cell frame which needs
    1735                 :       // to use the mComputedHeight of the cell instead of what the cell block passed in.
    1736                 :       // XXX It seems like this could lead to bugs with min-height and friends
    1737               0 :       if (cbrs->parentReflowState) {
    1738               0 :         fType = cbrs->frame->GetType();
    1739               0 :         if (IS_TABLE_CELL(fType)) {
    1740                 :           // use the cell's computed height 
    1741               0 :           aContainingBlockHeight = cbrs->mComputedHeight;
    1742                 :         }
    1743                 :       }
    1744                 :     }
    1745                 : 
    1746               0 :     InitOffsets(aContainingBlockWidth, aFrameType, aBorder, aPadding);
    1747                 : 
    1748               0 :     const nsStyleCoord &height = mStylePosition->mHeight;
    1749               0 :     nsStyleUnit heightUnit = height.GetUnit();
    1750                 : 
    1751                 :     // Check for a percentage based height and a containing block height
    1752                 :     // that depends on the content height
    1753                 :     // XXX twiddling heightUnit doesn't help anymore
    1754                 :     // FIXME Shouldn't we fix that?
    1755               0 :     if (height.HasPercent()) {
    1756               0 :       if (NS_AUTOHEIGHT == aContainingBlockHeight) {
    1757                 :         // this if clause enables %-height on replaced inline frames,
    1758                 :         // such as images.  See bug 54119.  The else clause "heightUnit = eStyleUnit_Auto;"
    1759                 :         // used to be called exclusively.
    1760               0 :         if (NS_FRAME_REPLACED(NS_CSS_FRAME_TYPE_INLINE) == mFrameType ||
    1761                 :             NS_FRAME_REPLACED_CONTAINS_BLOCK(
    1762                 :                 NS_CSS_FRAME_TYPE_INLINE) == mFrameType) {
    1763                 :           // Get the containing block reflow state
    1764               0 :           NS_ASSERTION(nsnull != cbrs, "no containing block");
    1765                 :           // in quirks mode, get the cb height using the special quirk method
    1766               0 :           if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode()) {
    1767               0 :             if (!IS_TABLE_CELL(fType)) {
    1768               0 :               aContainingBlockHeight = CalcQuirkContainingBlockHeight(cbrs);
    1769               0 :               if (aContainingBlockHeight == NS_AUTOHEIGHT) {
    1770               0 :                 heightUnit = eStyleUnit_Auto;
    1771                 :               }
    1772                 :             }
    1773                 :             else {
    1774               0 :               heightUnit = eStyleUnit_Auto;
    1775                 :             }
    1776                 :           }
    1777                 :           // in standard mode, use the cb height.  if it's "auto", as will be the case
    1778                 :           // by default in BODY, use auto height as per CSS2 spec.
    1779                 :           else 
    1780                 :           {
    1781               0 :             if (NS_AUTOHEIGHT != cbrs->mComputedHeight)
    1782               0 :               aContainingBlockHeight = cbrs->mComputedHeight;
    1783                 :             else
    1784               0 :               heightUnit = eStyleUnit_Auto;
    1785                 :           }
    1786                 :         }
    1787                 :         else {
    1788                 :           // default to interpreting the height like 'auto'
    1789               0 :           heightUnit = eStyleUnit_Auto;
    1790                 :         }
    1791                 :       }
    1792                 :     }
    1793                 : 
    1794                 :     // Compute our offsets if the element is relatively positioned.  We need
    1795                 :     // the correct containing block width and height here, which is why we need
    1796                 :     // to do it after all the quirks-n-such above.
    1797               0 :     if (NS_STYLE_POSITION_RELATIVE == mStyleDisplay->mPosition) {
    1798               0 :       ComputeRelativeOffsets(cbrs, aContainingBlockWidth, aContainingBlockHeight, aPresContext);
    1799                 :     } else {
    1800                 :       // Initialize offsets to 0
    1801               0 :       mComputedOffsets.SizeTo(0, 0, 0, 0);
    1802                 :     }
    1803                 : 
    1804                 :     // Calculate the computed values for min and max properties.  Note that
    1805                 :     // this MUST come after we've computed our border and padding.
    1806               0 :     ComputeMinMaxValues(aContainingBlockWidth, aContainingBlockHeight, cbrs);
    1807                 : 
    1808                 :     // Calculate the computed width and height. This varies by frame type
    1809                 : 
    1810               0 :     if (NS_CSS_FRAME_TYPE_INTERNAL_TABLE == mFrameType) {
    1811                 :       // Internal table elements. The rules vary depending on the type.
    1812                 :       // Calculate the computed width
    1813               0 :       bool rowOrRowGroup = false;
    1814               0 :       const nsStyleCoord &width = mStylePosition->mWidth;
    1815               0 :       nsStyleUnit widthUnit = width.GetUnit();
    1816               0 :       if ((NS_STYLE_DISPLAY_TABLE_ROW == mStyleDisplay->mDisplay) ||
    1817                 :           (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == mStyleDisplay->mDisplay)) {
    1818                 :         // 'width' property doesn't apply to table rows and row groups
    1819               0 :         widthUnit = eStyleUnit_Auto;
    1820               0 :         rowOrRowGroup = true;
    1821                 :       }
    1822                 : 
    1823                 :       // calc() acts like auto on internal table elements
    1824               0 :       if (eStyleUnit_Auto == widthUnit || width.IsCalcUnit()) {
    1825               0 :         mComputedWidth = availableWidth;
    1826                 : 
    1827               0 :         if ((mComputedWidth != NS_UNCONSTRAINEDSIZE) && !rowOrRowGroup){
    1828                 :           // Internal table elements don't have margins. Only tables and
    1829                 :           // cells have border and padding
    1830                 :           mComputedWidth -= mComputedBorderPadding.left +
    1831               0 :             mComputedBorderPadding.right;
    1832               0 :           if (mComputedWidth < 0)
    1833               0 :             mComputedWidth = 0;
    1834                 :         }
    1835               0 :         NS_ASSERTION(mComputedWidth >= 0, "Bogus computed width");
    1836                 :       
    1837                 :       } else {
    1838               0 :         NS_ASSERTION(widthUnit == mStylePosition->mWidth.GetUnit(),
    1839                 :                      "unexpected width unit change");
    1840                 :         mComputedWidth = ComputeWidthValue(aContainingBlockWidth,
    1841                 :                                            mStylePosition->mBoxSizing,
    1842               0 :                                            mStylePosition->mWidth);
    1843                 :       }
    1844                 : 
    1845                 :       // Calculate the computed height
    1846               0 :       if ((NS_STYLE_DISPLAY_TABLE_COLUMN == mStyleDisplay->mDisplay) ||
    1847                 :           (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == mStyleDisplay->mDisplay)) {
    1848                 :         // 'height' property doesn't apply to table columns and column groups
    1849               0 :         heightUnit = eStyleUnit_Auto;
    1850                 :       }
    1851                 :       // calc() acts like 'auto' on internal table elements
    1852               0 :       if (eStyleUnit_Auto == heightUnit || height.IsCalcUnit()) {
    1853               0 :         mComputedHeight = NS_AUTOHEIGHT;
    1854                 :       } else {
    1855               0 :         NS_ASSERTION(heightUnit == mStylePosition->mHeight.GetUnit(),
    1856                 :                      "unexpected height unit change");
    1857                 :         mComputedHeight = nsLayoutUtils::
    1858               0 :           ComputeHeightValue(aContainingBlockHeight, mStylePosition->mHeight);
    1859                 :       }
    1860                 : 
    1861                 :       // Doesn't apply to table elements
    1862               0 :       mComputedMinWidth = mComputedMinHeight = 0;
    1863               0 :       mComputedMaxWidth = mComputedMaxHeight = NS_UNCONSTRAINEDSIZE;
    1864                 : 
    1865               0 :     } else if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE) {
    1866                 :       // XXX not sure if this belongs here or somewhere else - cwk
    1867                 :       InitAbsoluteConstraints(aPresContext, cbrs, aContainingBlockWidth,
    1868               0 :                               aContainingBlockHeight, aFrameType);
    1869                 :     } else {
    1870               0 :       AutoMaybeNullInflationContainer an(frame);
    1871                 : 
    1872                 :       bool isBlock =
    1873               0 :         NS_CSS_FRAME_TYPE_BLOCK == NS_FRAME_GET_TYPE(mFrameType);
    1874                 :       // make sure legend frames with display:block and width:auto still
    1875                 :       // shrink-wrap
    1876               0 :       bool shrinkWrap = !isBlock || aFrameType == nsGkAtoms::legendFrame;
    1877                 :       nsSize size =
    1878                 :         frame->ComputeSize(rendContext,
    1879                 :                            nsSize(aContainingBlockWidth,
    1880                 :                                   aContainingBlockHeight),
    1881                 :                            availableWidth,
    1882                 :                            nsSize(mComputedMargin.LeftRight(),
    1883                 :                                   mComputedMargin.TopBottom()),
    1884               0 :                            nsSize(mComputedBorderPadding.LeftRight() -
    1885               0 :                                     mComputedPadding.LeftRight(),
    1886               0 :                                   mComputedBorderPadding.TopBottom() -
    1887               0 :                                     mComputedPadding.TopBottom()),
    1888                 :                            nsSize(mComputedPadding.LeftRight(),
    1889                 :                                   mComputedPadding.TopBottom()),
    1890               0 :                            shrinkWrap);
    1891                 : 
    1892               0 :       mComputedWidth = size.width;
    1893               0 :       mComputedHeight = size.height;
    1894               0 :       NS_ASSERTION(mComputedWidth >= 0, "Bogus width");
    1895               0 :       NS_ASSERTION(mComputedHeight == NS_UNCONSTRAINEDSIZE ||
    1896                 :                    mComputedHeight >= 0, "Bogus height");
    1897                 : 
    1898                 :       // Exclude inline tables from the block margin calculations
    1899               0 :       if (isBlock && !IsSideCaption(frame, mStyleDisplay) &&
    1900               0 :           frame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE_TABLE)
    1901               0 :         CalculateBlockSideMargins(availableWidth, mComputedWidth, aFrameType);
    1902                 :     }
    1903                 :   }
    1904                 :   // Check for blinking text and permission to display it
    1905               0 :   mFlags.mBlinks = (parentReflowState && parentReflowState->mFlags.mBlinks);
    1906               0 :   if (!mFlags.mBlinks && BlinkIsAllowed()) {
    1907               0 :     const nsStyleTextReset* st = frame->GetStyleTextReset();
    1908               0 :     mFlags.mBlinks = (st->mTextBlink != NS_STYLE_TEXT_BLINK_NONE);
    1909                 :   }
    1910                 : 
    1911               0 :   if (nsLayoutUtils::IsContainerForFontSizeInflation(frame)) {
    1912               0 :     aPresContext->mCurrentInflationContainer = frame;
    1913               0 :     aPresContext->mCurrentInflationContainerWidth = mComputedWidth;
    1914                 :   }
    1915               0 : }
    1916                 : 
    1917                 : static void
    1918               0 : UpdateProp(FrameProperties& aProps,
    1919                 :            const FramePropertyDescriptor* aProperty,
    1920                 :            bool aNeeded,
    1921                 :            nsMargin& aNewValue)
    1922                 : {
    1923               0 :   if (aNeeded) {
    1924               0 :     nsMargin* propValue = static_cast<nsMargin*>(aProps.Get(aProperty));
    1925               0 :     if (propValue) {
    1926               0 :       *propValue = aNewValue;
    1927                 :     } else {
    1928               0 :       aProps.Set(aProperty, new nsMargin(aNewValue));
    1929                 :     }
    1930                 :   } else {
    1931               0 :     aProps.Delete(aProperty);
    1932                 :   }
    1933               0 : }
    1934                 : 
    1935                 : void
    1936               0 : nsCSSOffsetState::InitOffsets(nscoord aContainingBlockWidth,
    1937                 :                               nsIAtom* aFrameType,
    1938                 :                               const nsMargin *aBorder,
    1939                 :                               const nsMargin *aPadding)
    1940                 : {
    1941               0 :   DISPLAY_INIT_OFFSETS(frame, this, aContainingBlockWidth, aBorder, aPadding);
    1942                 : 
    1943                 :   // Since we are in reflow, we don't need to store these properties anymore
    1944                 :   // unless they are dependent on width, in which case we store the new value.
    1945               0 :   nsPresContext *presContext = frame->PresContext();
    1946               0 :   FrameProperties props(presContext->PropertyTable(), frame);
    1947               0 :   props.Delete(nsIFrame::UsedBorderProperty());
    1948                 : 
    1949                 :   // Compute margins from the specified margin style information. These
    1950                 :   // become the default computed values, and may be adjusted below
    1951                 :   // XXX fix to provide 0,0 for the top&bottom margins for
    1952                 :   // inline-non-replaced elements
    1953               0 :   bool needMarginProp = ComputeMargin(aContainingBlockWidth);
    1954                 :   // XXX We need to include 'auto' horizontal margins in this too!
    1955                 :   // ... but if we did that, we'd need to fix nsFrame::GetUsedMargin
    1956                 :   // to use it even when the margins are all zero (since sometimes
    1957                 :   // they get treated as auto)
    1958                 :   ::UpdateProp(props, nsIFrame::UsedMarginProperty(), needMarginProp,
    1959               0 :                mComputedMargin);
    1960                 : 
    1961                 : 
    1962               0 :   const nsStyleDisplay *disp = frame->GetStyleDisplay();
    1963               0 :   bool isThemed = frame->IsThemed(disp);
    1964                 :   bool needPaddingProp;
    1965               0 :   nsIntMargin widget;
    1966               0 :   if (isThemed &&
    1967               0 :       presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
    1968                 :                                                 frame, disp->mAppearance,
    1969               0 :                                                 &widget)) {
    1970               0 :     mComputedPadding.top = presContext->DevPixelsToAppUnits(widget.top);
    1971               0 :     mComputedPadding.right = presContext->DevPixelsToAppUnits(widget.right);
    1972               0 :     mComputedPadding.bottom = presContext->DevPixelsToAppUnits(widget.bottom);
    1973               0 :     mComputedPadding.left = presContext->DevPixelsToAppUnits(widget.left);
    1974               0 :     needPaddingProp = false;
    1975                 :   }
    1976               0 :   else if (aPadding) { // padding is an input arg
    1977               0 :     mComputedPadding = *aPadding;
    1978               0 :     needPaddingProp = frame->GetStylePadding()->IsWidthDependent();
    1979                 :   }
    1980                 :   else {
    1981               0 :     needPaddingProp = ComputePadding(aContainingBlockWidth, aFrameType);
    1982                 :   }
    1983                 : 
    1984               0 :   if (isThemed) {
    1985               0 :     nsIntMargin widget;
    1986               0 :     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
    1987                 :                                              frame, disp->mAppearance,
    1988               0 :                                              &widget);
    1989                 :     mComputedBorderPadding.top =
    1990               0 :       presContext->DevPixelsToAppUnits(widget.top);
    1991                 :     mComputedBorderPadding.right =
    1992               0 :       presContext->DevPixelsToAppUnits(widget.right);
    1993                 :     mComputedBorderPadding.bottom =
    1994               0 :       presContext->DevPixelsToAppUnits(widget.bottom);
    1995                 :     mComputedBorderPadding.left =
    1996               0 :       presContext->DevPixelsToAppUnits(widget.left);
    1997                 :   }
    1998               0 :   else if (aBorder) {  // border is an input arg
    1999               0 :     mComputedBorderPadding = *aBorder;
    2000                 :   }
    2001                 :   else {
    2002               0 :     mComputedBorderPadding = frame->GetStyleBorder()->GetActualBorder();
    2003                 :   }
    2004               0 :   mComputedBorderPadding += mComputedPadding;
    2005                 : 
    2006               0 :   if (aFrameType == nsGkAtoms::tableFrame) {
    2007               0 :     nsTableFrame *tableFrame = static_cast<nsTableFrame*>(frame);
    2008                 : 
    2009               0 :     if (tableFrame->IsBorderCollapse()) {
    2010                 :       // border-collapsed tables don't use any of their padding, and
    2011                 :       // only part of their border.  We need to do this here before we
    2012                 :       // try to do anything like handling 'auto' widths,
    2013                 :       // '-moz-box-sizing', or 'auto' margins.
    2014               0 :       mComputedPadding.SizeTo(0,0,0,0);
    2015               0 :       mComputedBorderPadding = tableFrame->GetIncludedOuterBCBorder();
    2016                 :     }
    2017                 : 
    2018                 :     // The margin is inherited to the outer table frame via
    2019                 :     // the ::-moz-table-outer rule in ua.css.
    2020               0 :     mComputedMargin.SizeTo(0, 0, 0, 0);
    2021               0 :   } else if (aFrameType == nsGkAtoms::scrollbarFrame) {
    2022                 :     // scrollbars may have had their width or height smashed to zero
    2023                 :     // by the associated scrollframe, in which case we must not report
    2024                 :     // any padding or border.
    2025               0 :     nsSize size(frame->GetSize());
    2026               0 :     if (size.width == 0 || size.height == 0) {
    2027               0 :       mComputedPadding.SizeTo(0,0,0,0);
    2028               0 :       mComputedBorderPadding.SizeTo(0,0,0,0);
    2029                 :     }
    2030                 :   }
    2031                 :   ::UpdateProp(props, nsIFrame::UsedPaddingProperty(), needPaddingProp,
    2032               0 :                mComputedPadding);
    2033               0 : }
    2034                 : 
    2035                 : // This code enforces section 10.3.3 of the CSS2 spec for this formula:
    2036                 : //
    2037                 : // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' +
    2038                 : //   'padding-right' + 'border-right-width' + 'margin-right'
    2039                 : //   = width of containing block 
    2040                 : //
    2041                 : // Note: the width unit is not auto when this is called
    2042                 : void
    2043               0 : nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailWidth,
    2044                 :                                              nscoord aComputedWidth,
    2045                 :                                              nsIAtom* aFrameType)
    2046                 : {
    2047               0 :   NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aComputedWidth &&
    2048                 :                    NS_UNCONSTRAINEDSIZE != aAvailWidth,
    2049                 :                    "have unconstrained width; this should only result from "
    2050                 :                    "very large sizes, not attempts at intrinsic width "
    2051                 :                    "calculation");
    2052                 : 
    2053                 :   nscoord sum = mComputedMargin.left + mComputedBorderPadding.left +
    2054               0 :     aComputedWidth + mComputedBorderPadding.right + mComputedMargin.right;
    2055               0 :   if (sum == aAvailWidth)
    2056                 :     // The sum is already correct
    2057               0 :     return;
    2058                 : 
    2059                 :   // Determine the left and right margin values. The width value
    2060                 :   // remains constant while we do this.
    2061                 : 
    2062                 :   // Calculate how much space is available for margins
    2063               0 :   nscoord availMarginSpace = aAvailWidth - sum;
    2064                 : 
    2065                 :   // If the available margin space is negative, then don't follow the
    2066                 :   // usual overconstraint rules.
    2067               0 :   if (availMarginSpace < 0) {
    2068               0 :     if (mCBReflowState &&
    2069                 :         mCBReflowState->mStyleVisibility->mDirection == NS_STYLE_DIRECTION_RTL) {
    2070               0 :       mComputedMargin.left += availMarginSpace;
    2071                 :     } else {
    2072               0 :       mComputedMargin.right += availMarginSpace;
    2073                 :     }
    2074               0 :     return;
    2075                 :   }
    2076                 : 
    2077                 :   // The css2 spec clearly defines how block elements should behave
    2078                 :   // in section 10.3.3.
    2079                 :   bool isAutoLeftMargin =
    2080               0 :     eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit();
    2081                 :   bool isAutoRightMargin =
    2082               0 :     eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit();
    2083               0 :   if (!isAutoLeftMargin && !isAutoRightMargin) {
    2084                 :     // Neither margin is 'auto' so we're over constrained. Use the
    2085                 :     // 'direction' property of the parent to tell which margin to
    2086                 :     // ignore
    2087                 :     // First check if there is an HTML alignment that we should honor
    2088               0 :     const nsHTMLReflowState* prs = parentReflowState;
    2089               0 :     if (aFrameType == nsGkAtoms::tableFrame) {
    2090               0 :       NS_ASSERTION(prs->frame->GetType() == nsGkAtoms::tableOuterFrame,
    2091                 :                    "table not inside outer table");
    2092                 :       // Center the table within the outer table based on the alignment
    2093                 :       // of the outer table's parent.
    2094               0 :       prs = prs->parentReflowState;
    2095                 :     }
    2096               0 :     if (prs &&
    2097                 :         (prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_LEFT ||
    2098                 :          prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
    2099                 :          prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)) {
    2100                 :       isAutoLeftMargin =
    2101               0 :         prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_LEFT;
    2102                 :       isAutoRightMargin =
    2103               0 :         prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_RIGHT;
    2104                 :     }
    2105                 :     // Otherwise apply the CSS rules, and ignore one margin by forcing
    2106                 :     // it to 'auto', depending on 'direction'.
    2107               0 :     else if (mCBReflowState &&
    2108                 :              NS_STYLE_DIRECTION_RTL == mCBReflowState->mStyleVisibility->mDirection) {
    2109               0 :       isAutoLeftMargin = true;
    2110                 :     }
    2111                 :     else {
    2112               0 :       isAutoRightMargin = true;
    2113                 :     }
    2114                 :   }
    2115                 : 
    2116                 :   // Logic which is common to blocks and tables
    2117                 :   // The computed margins need not be zero because the 'auto' could come from
    2118                 :   // overconstraint or from HTML alignment so values need to be accumulated
    2119                 : 
    2120               0 :   if (isAutoLeftMargin) {
    2121               0 :     if (isAutoRightMargin) {
    2122                 :       // Both margins are 'auto' so the computed addition should be equal
    2123               0 :       nscoord forLeft = availMarginSpace / 2;
    2124               0 :       mComputedMargin.left  += forLeft;
    2125               0 :       mComputedMargin.right += availMarginSpace - forLeft;
    2126                 :     } else {
    2127               0 :       mComputedMargin.left += availMarginSpace;
    2128                 :     }
    2129               0 :   } else if (isAutoRightMargin) {
    2130               0 :     mComputedMargin.right += availMarginSpace;
    2131                 :   }
    2132                 : }
    2133                 : 
    2134                 : #define NORMAL_LINE_HEIGHT_FACTOR 1.2f    // in term of emHeight 
    2135                 : // For "normal" we use the font's normal line height (em height + leading).
    2136                 : // If both internal leading and  external leading specified by font itself
    2137                 : // are zeros, we should compensate this by creating extra (external) leading 
    2138                 : // in eCompensateLeading mode. This is necessary because without this 
    2139                 : // compensation, normal line height might looks too tight. 
    2140                 : 
    2141                 : // For risk management, we use preference to control the behavior, and 
    2142                 : // eNoExternalLeading is the old behavior.
    2143                 : static nscoord
    2144               0 : GetNormalLineHeight(nsFontMetrics* aFontMetrics)
    2145                 : {
    2146               0 :   NS_PRECONDITION(nsnull != aFontMetrics, "no font metrics");
    2147                 : 
    2148                 :   nscoord normalLineHeight;
    2149                 : 
    2150               0 :   nscoord externalLeading = aFontMetrics->ExternalLeading();
    2151               0 :   nscoord internalLeading = aFontMetrics->InternalLeading();
    2152               0 :   nscoord emHeight = aFontMetrics->EmHeight();
    2153               0 :   switch (GetNormalLineHeightCalcControl()) {
    2154                 :   case eIncludeExternalLeading:
    2155               0 :     normalLineHeight = emHeight+ internalLeading + externalLeading;
    2156               0 :     break;
    2157                 :   case eCompensateLeading:
    2158               0 :     if (!internalLeading && !externalLeading)
    2159               0 :       normalLineHeight = NSToCoordRound(emHeight * NORMAL_LINE_HEIGHT_FACTOR);
    2160                 :     else
    2161               0 :       normalLineHeight = emHeight+ internalLeading + externalLeading;
    2162               0 :     break;
    2163                 :   default:
    2164                 :     //case eNoExternalLeading:
    2165               0 :     normalLineHeight = emHeight + internalLeading;
    2166                 :   }
    2167               0 :   return normalLineHeight;
    2168                 : }
    2169                 : 
    2170                 : static inline nscoord
    2171               0 : ComputeLineHeight(nsStyleContext* aStyleContext,
    2172                 :                   nscoord aBlockHeight,
    2173                 :                   float aFontSizeInflation)
    2174                 : {
    2175               0 :   const nsStyleCoord& lhCoord = aStyleContext->GetStyleText()->mLineHeight;
    2176                 : 
    2177               0 :   if (lhCoord.GetUnit() == eStyleUnit_Coord) {
    2178               0 :     nscoord result = lhCoord.GetCoordValue();
    2179               0 :     if (aFontSizeInflation != 1.0f) {
    2180               0 :       result = NSToCoordRound(result * aFontSizeInflation);
    2181                 :     }
    2182               0 :     return result;
    2183                 :   }
    2184                 : 
    2185               0 :   if (lhCoord.GetUnit() == eStyleUnit_Factor)
    2186                 :     // For factor units the computed value of the line-height property 
    2187                 :     // is found by multiplying the factor by the font's computed size
    2188                 :     // (adjusted for min-size prefs and text zoom).
    2189               0 :     return NSToCoordRound(lhCoord.GetFactorValue() * aFontSizeInflation *
    2190               0 :                           aStyleContext->GetStyleFont()->mFont.size);
    2191                 : 
    2192               0 :   NS_ASSERTION(lhCoord.GetUnit() == eStyleUnit_Normal ||
    2193                 :                lhCoord.GetUnit() == eStyleUnit_Enumerated,
    2194                 :                "bad line-height unit");
    2195                 :   
    2196               0 :   if (lhCoord.GetUnit() == eStyleUnit_Enumerated) {
    2197               0 :     NS_ASSERTION(lhCoord.GetIntValue() == NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT,
    2198                 :                  "bad line-height value");
    2199               0 :     if (aBlockHeight != NS_AUTOHEIGHT) {
    2200               0 :       return aBlockHeight;
    2201                 :     }
    2202                 :   }
    2203                 : 
    2204               0 :   nsRefPtr<nsFontMetrics> fm;
    2205                 :   nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext,
    2206                 :                                                getter_AddRefs(fm),
    2207               0 :                                                aFontSizeInflation);
    2208               0 :   return GetNormalLineHeight(fm);
    2209                 : }
    2210                 : 
    2211                 : nscoord
    2212               0 : nsHTMLReflowState::CalcLineHeight() const
    2213                 : {
    2214                 :   nscoord blockHeight =
    2215               0 :     nsLayoutUtils::IsNonWrapperBlock(frame) ? mComputedHeight :
    2216               0 :     (mCBReflowState ? mCBReflowState->mComputedHeight : NS_AUTOHEIGHT);
    2217                 : 
    2218                 :   return CalcLineHeight(frame->GetStyleContext(), blockHeight,
    2219                 :                         nsLayoutUtils::FontSizeInflationFor(frame,
    2220               0 :                           nsLayoutUtils::eInReflow));
    2221                 : }
    2222                 : 
    2223                 : /* static */ nscoord
    2224               0 : nsHTMLReflowState::CalcLineHeight(nsStyleContext* aStyleContext,
    2225                 :                                   nscoord aBlockHeight,
    2226                 :                                   float aFontSizeInflation)
    2227                 : {
    2228               0 :   NS_PRECONDITION(aStyleContext, "Must have a style context");
    2229                 : 
    2230                 :   nscoord lineHeight =
    2231               0 :     ComputeLineHeight(aStyleContext, aBlockHeight, aFontSizeInflation);
    2232                 : 
    2233               0 :   NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up");
    2234                 : 
    2235               0 :   return lineHeight;
    2236                 : }
    2237                 : 
    2238                 : bool
    2239               0 : nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth)
    2240                 : {
    2241                 :   // If style style can provide us the margin directly, then use it.
    2242               0 :   const nsStyleMargin *styleMargin = frame->GetStyleMargin();
    2243               0 :   bool isWidthDependent = !styleMargin->GetMargin(mComputedMargin);
    2244               0 :   if (isWidthDependent) {
    2245                 :     // We have to compute the value
    2246                 :     mComputedMargin.left = nsLayoutUtils::
    2247                 :       ComputeWidthDependentValue(aContainingBlockWidth,
    2248               0 :                                  styleMargin->mMargin.GetLeft());
    2249                 :     mComputedMargin.right = nsLayoutUtils::
    2250                 :       ComputeWidthDependentValue(aContainingBlockWidth,
    2251               0 :                                  styleMargin->mMargin.GetRight());
    2252                 : 
    2253                 :     // According to the CSS2 spec, margin percentages are
    2254                 :     // calculated with respect to the *width* of the containing
    2255                 :     // block, even for margin-top and margin-bottom.
    2256                 :     // XXX This isn't true for page boxes, if we implement them.
    2257                 :     mComputedMargin.top = nsLayoutUtils::
    2258                 :       ComputeWidthDependentValue(aContainingBlockWidth,
    2259               0 :                                  styleMargin->mMargin.GetTop());
    2260                 :     mComputedMargin.bottom = nsLayoutUtils::
    2261                 :       ComputeWidthDependentValue(aContainingBlockWidth,
    2262               0 :                                  styleMargin->mMargin.GetBottom());
    2263                 :   }
    2264               0 :   return isWidthDependent;
    2265                 : }
    2266                 : 
    2267                 : bool
    2268               0 : nsCSSOffsetState::ComputePadding(nscoord aContainingBlockWidth, nsIAtom* aFrameType)
    2269                 : {
    2270                 :   // If style can provide us the padding directly, then use it.
    2271               0 :   const nsStylePadding *stylePadding = frame->GetStylePadding();
    2272               0 :   bool isWidthDependent = !stylePadding->GetPadding(mComputedPadding);
    2273                 :   // a table row/col group, row/col doesn't have padding
    2274                 :   // XXXldb Neither do border-collapse tables.
    2275               0 :   if (nsGkAtoms::tableRowGroupFrame == aFrameType ||
    2276                 :       nsGkAtoms::tableColGroupFrame == aFrameType ||
    2277                 :       nsGkAtoms::tableRowFrame      == aFrameType ||
    2278                 :       nsGkAtoms::tableColFrame      == aFrameType) {
    2279               0 :     mComputedPadding.SizeTo(0,0,0,0);
    2280                 :   }
    2281               0 :   else if (isWidthDependent) {
    2282                 :     // We have to compute the value
    2283                 :     // clamp negative calc() results to 0
    2284                 :     mComputedPadding.left = NS_MAX(0, nsLayoutUtils::
    2285                 :       ComputeWidthDependentValue(aContainingBlockWidth,
    2286               0 :                                  stylePadding->mPadding.GetLeft()));
    2287                 :     mComputedPadding.right = NS_MAX(0, nsLayoutUtils::
    2288                 :       ComputeWidthDependentValue(aContainingBlockWidth,
    2289               0 :                                  stylePadding->mPadding.GetRight()));
    2290                 : 
    2291                 :     // According to the CSS2 spec, percentages are calculated with respect to
    2292                 :     // containing block width for padding-top and padding-bottom
    2293                 :     mComputedPadding.top = NS_MAX(0, nsLayoutUtils::
    2294                 :       ComputeWidthDependentValue(aContainingBlockWidth,
    2295               0 :                                  stylePadding->mPadding.GetTop()));
    2296                 :     mComputedPadding.bottom = NS_MAX(0, nsLayoutUtils::
    2297                 :       ComputeWidthDependentValue(aContainingBlockWidth,
    2298               0 :                                  stylePadding->mPadding.GetBottom()));
    2299                 :   }
    2300               0 :   return isWidthDependent;
    2301                 : }
    2302                 : 
    2303                 : void
    2304               0 : nsHTMLReflowState::ApplyMinMaxConstraints(nscoord* aFrameWidth,
    2305                 :                                           nscoord* aFrameHeight) const
    2306                 : {
    2307               0 :   if (aFrameWidth) {
    2308               0 :     if (NS_UNCONSTRAINEDSIZE != mComputedMaxWidth) {
    2309               0 :       *aFrameWidth = NS_MIN(*aFrameWidth, mComputedMaxWidth);
    2310                 :     }
    2311               0 :     *aFrameWidth = NS_MAX(*aFrameWidth, mComputedMinWidth);
    2312                 :   }
    2313                 : 
    2314               0 :   if (aFrameHeight) {
    2315               0 :     if (NS_UNCONSTRAINEDSIZE != mComputedMaxHeight) {
    2316               0 :       *aFrameHeight = NS_MIN(*aFrameHeight, mComputedMaxHeight);
    2317                 :     }
    2318               0 :     *aFrameHeight = NS_MAX(*aFrameHeight, mComputedMinHeight);
    2319                 :   }
    2320               0 : }
    2321                 : 
    2322                 : void
    2323               0 : nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth,
    2324                 :                                        nscoord aContainingBlockHeight,
    2325                 :                                        const nsHTMLReflowState* aContainingBlockRS)
    2326                 : {
    2327                 :   mComputedMinWidth = ComputeWidthValue(aContainingBlockWidth,
    2328                 :                                         mStylePosition->mBoxSizing,
    2329               0 :                                         mStylePosition->mMinWidth);
    2330                 : 
    2331               0 :   if (eStyleUnit_None == mStylePosition->mMaxWidth.GetUnit()) {
    2332                 :     // Specified value of 'none'
    2333               0 :     mComputedMaxWidth = NS_UNCONSTRAINEDSIZE;  // no limit
    2334                 :   } else {
    2335                 :     mComputedMaxWidth = ComputeWidthValue(aContainingBlockWidth,
    2336                 :                                           mStylePosition->mBoxSizing,
    2337               0 :                                           mStylePosition->mMaxWidth);
    2338                 :   }
    2339                 : 
    2340                 :   // If the computed value of 'min-width' is greater than the value of
    2341                 :   // 'max-width', 'max-width' is set to the value of 'min-width'
    2342               0 :   if (mComputedMinWidth > mComputedMaxWidth) {
    2343               0 :     mComputedMaxWidth = mComputedMinWidth;
    2344                 :   }
    2345                 : 
    2346                 :   // Check for percentage based values and a containing block height that
    2347                 :   // depends on the content height. Treat them like 'auto'
    2348                 :   // Likewise, check for calc() on internal table elements; calc() on
    2349                 :   // such elements is unsupported.
    2350               0 :   const nsStyleCoord &minHeight = mStylePosition->mMinHeight;
    2351               0 :   if ((NS_AUTOHEIGHT == aContainingBlockHeight &&
    2352               0 :        minHeight.HasPercent()) ||
    2353                 :       (mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE &&
    2354               0 :        minHeight.IsCalcUnit())) {
    2355               0 :     mComputedMinHeight = 0;
    2356                 :   } else {
    2357                 :     mComputedMinHeight = nsLayoutUtils::
    2358               0 :       ComputeHeightValue(aContainingBlockHeight, minHeight);
    2359                 :   }
    2360               0 :   const nsStyleCoord &maxHeight = mStylePosition->mMaxHeight;
    2361               0 :   nsStyleUnit maxHeightUnit = maxHeight.GetUnit();
    2362               0 :   if (eStyleUnit_None == maxHeightUnit) {
    2363                 :     // Specified value of 'none'
    2364               0 :     mComputedMaxHeight = NS_UNCONSTRAINEDSIZE;  // no limit
    2365                 :   } else {
    2366                 :     // Check for percentage based values and a containing block height that
    2367                 :     // depends on the content height. Treat them like 'auto'
    2368                 :     // Likewise, check for calc() on internal table elements; calc() on
    2369                 :     // such elements is unsupported.
    2370               0 :     if ((NS_AUTOHEIGHT == aContainingBlockHeight && 
    2371               0 :          maxHeight.HasPercent()) ||
    2372                 :         (mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE &&
    2373               0 :          maxHeight.IsCalcUnit())) {
    2374               0 :       mComputedMaxHeight = NS_UNCONSTRAINEDSIZE;
    2375                 :     } else {
    2376                 :       mComputedMaxHeight = nsLayoutUtils::
    2377               0 :         ComputeHeightValue(aContainingBlockHeight, maxHeight);
    2378                 :     }
    2379                 :   }
    2380                 : 
    2381                 :   // If the computed value of 'min-height' is greater than the value of
    2382                 :   // 'max-height', 'max-height' is set to the value of 'min-height'
    2383               0 :   if (mComputedMinHeight > mComputedMaxHeight) {
    2384               0 :     mComputedMaxHeight = mComputedMinHeight;
    2385                 :   }
    2386               0 : }
    2387                 : 
    2388                 : void
    2389               0 : nsHTMLReflowState::SetTruncated(const nsHTMLReflowMetrics& aMetrics,
    2390                 :                                 nsReflowStatus* aStatus) const
    2391                 : {
    2392               0 :   if (availableHeight != NS_UNCONSTRAINEDSIZE &&
    2393                 :       availableHeight < aMetrics.height &&
    2394               0 :       !mFlags.mIsTopOfPage) {
    2395               0 :     *aStatus |= NS_FRAME_TRUNCATED;
    2396                 :   } else {
    2397               0 :     *aStatus &= ~NS_FRAME_TRUNCATED;
    2398                 :   }
    2399               0 : }

Generated by: LCOV version 1.7