michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* struct containing the input to nsIFrame::Reflow */ michael@0: michael@0: #ifndef nsHTMLReflowState_h___ michael@0: #define nsHTMLReflowState_h___ michael@0: michael@0: #include "nsMargin.h" michael@0: #include "nsStyleCoord.h" michael@0: #include "nsIFrame.h" michael@0: #include "mozilla/Assertions.h" michael@0: #include michael@0: michael@0: class nsPresContext; michael@0: class nsRenderingContext; michael@0: class nsFloatManager; michael@0: class nsLineLayout; michael@0: class nsIPercentHeightObserver; michael@0: struct nsHypotheticalBox; michael@0: michael@0: /** michael@0: * @return aValue clamped to [aMinValue, aMaxValue]. michael@0: * michael@0: * @note This function needs to handle aMinValue > aMaxValue. In that case, michael@0: * aMinValue is returned. michael@0: * @see http://www.w3.org/TR/CSS21/visudet.html#min-max-widths michael@0: * @see http://www.w3.org/TR/CSS21/visudet.html#min-max-heights michael@0: */ michael@0: template michael@0: NumericType michael@0: NS_CSS_MINMAX(NumericType aValue, NumericType aMinValue, NumericType aMaxValue) michael@0: { michael@0: NumericType result = aValue; michael@0: if (aMaxValue < result) michael@0: result = aMaxValue; michael@0: if (aMinValue > result) michael@0: result = aMinValue; michael@0: return result; michael@0: } michael@0: michael@0: /** michael@0: * CSS Frame type. Included as part of the reflow state. michael@0: */ michael@0: typedef uint32_t nsCSSFrameType; michael@0: michael@0: #define NS_CSS_FRAME_TYPE_UNKNOWN 0 michael@0: #define NS_CSS_FRAME_TYPE_INLINE 1 michael@0: #define NS_CSS_FRAME_TYPE_BLOCK 2 /* block-level in normal flow */ michael@0: #define NS_CSS_FRAME_TYPE_FLOATING 3 michael@0: #define NS_CSS_FRAME_TYPE_ABSOLUTE 4 michael@0: #define NS_CSS_FRAME_TYPE_INTERNAL_TABLE 5 /* row group frame, row frame, cell frame, ... */ michael@0: michael@0: /** michael@0: * Bit-flag that indicates whether the element is replaced. Applies to inline, michael@0: * block-level, floating, and absolutely positioned elements michael@0: */ michael@0: #define NS_CSS_FRAME_TYPE_REPLACED 0x08000 michael@0: michael@0: /** michael@0: * Bit-flag that indicates that the element is replaced and contains a block michael@0: * (eg some form controls). Applies to inline, block-level, floating, and michael@0: * absolutely positioned elements. Mutually exclusive with michael@0: * NS_CSS_FRAME_TYPE_REPLACED. michael@0: */ michael@0: #define NS_CSS_FRAME_TYPE_REPLACED_CONTAINS_BLOCK 0x10000 michael@0: michael@0: /** michael@0: * Helper macros for telling whether items are replaced michael@0: */ michael@0: #define NS_FRAME_IS_REPLACED_NOBLOCK(_ft) \ michael@0: (NS_CSS_FRAME_TYPE_REPLACED == ((_ft) & NS_CSS_FRAME_TYPE_REPLACED)) michael@0: michael@0: #define NS_FRAME_IS_REPLACED(_ft) \ michael@0: (NS_FRAME_IS_REPLACED_NOBLOCK(_ft) || \ michael@0: NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(_ft)) michael@0: michael@0: #define NS_FRAME_REPLACED(_ft) \ michael@0: (NS_CSS_FRAME_TYPE_REPLACED | (_ft)) michael@0: michael@0: #define NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(_ft) \ michael@0: (NS_CSS_FRAME_TYPE_REPLACED_CONTAINS_BLOCK == \ michael@0: ((_ft) & NS_CSS_FRAME_TYPE_REPLACED_CONTAINS_BLOCK)) michael@0: michael@0: #define NS_FRAME_REPLACED_CONTAINS_BLOCK(_ft) \ michael@0: (NS_CSS_FRAME_TYPE_REPLACED_CONTAINS_BLOCK | (_ft)) michael@0: michael@0: /** michael@0: * A macro to extract the type. Masks off the 'replaced' bit-flag michael@0: */ michael@0: #define NS_FRAME_GET_TYPE(_ft) \ michael@0: ((_ft) & ~(NS_CSS_FRAME_TYPE_REPLACED | \ michael@0: NS_CSS_FRAME_TYPE_REPLACED_CONTAINS_BLOCK)) michael@0: michael@0: // A base class of nsHTMLReflowState that computes only the padding, michael@0: // border, and margin, since those values are needed more often. michael@0: struct nsCSSOffsetState { michael@0: public: michael@0: typedef mozilla::WritingMode WritingMode; michael@0: typedef mozilla::LogicalMargin LogicalMargin; michael@0: michael@0: // the frame being reflowed michael@0: nsIFrame* frame; michael@0: michael@0: // rendering context to use for measurement michael@0: nsRenderingContext* rendContext; michael@0: michael@0: const nsMargin& ComputedPhysicalMargin() const { return mComputedMargin; } michael@0: const nsMargin& ComputedPhysicalBorderPadding() const { return mComputedBorderPadding; } michael@0: const nsMargin& ComputedPhysicalPadding() const { return mComputedPadding; } michael@0: michael@0: // We may need to eliminate the (few) users of these writable-reference accessors michael@0: // as part of migrating to logical coordinates. michael@0: nsMargin& ComputedPhysicalMargin() { return mComputedMargin; } michael@0: nsMargin& ComputedPhysicalBorderPadding() { return mComputedBorderPadding; } michael@0: nsMargin& ComputedPhysicalPadding() { return mComputedPadding; } michael@0: michael@0: LogicalMargin ComputedLogicalMargin() const michael@0: { return LogicalMargin(mWritingMode, mComputedMargin); } michael@0: LogicalMargin ComputedLogicalBorderPadding() const michael@0: { return LogicalMargin(mWritingMode, mComputedBorderPadding); } michael@0: LogicalMargin ComputedLogicalPadding() const michael@0: { return LogicalMargin(mWritingMode, mComputedPadding); } michael@0: michael@0: WritingMode GetWritingMode() const { return mWritingMode; } michael@0: michael@0: protected: michael@0: // cached copy of the frame's writing-mode, for logical coordinates michael@0: WritingMode mWritingMode; michael@0: michael@0: // These are PHYSICAL coordinates (for now). michael@0: // Will probably become logical in due course. michael@0: michael@0: // Computed margin values michael@0: nsMargin mComputedMargin; michael@0: michael@0: // Cached copy of the border + padding values michael@0: nsMargin mComputedBorderPadding; michael@0: michael@0: // Computed padding values michael@0: nsMargin mComputedPadding; michael@0: michael@0: public: michael@0: // Callers using this constructor must call InitOffsets on their own. michael@0: nsCSSOffsetState(nsIFrame *aFrame, nsRenderingContext *aRenderingContext) michael@0: : frame(aFrame) michael@0: , rendContext(aRenderingContext) michael@0: , mWritingMode(aFrame->GetWritingMode()) michael@0: { michael@0: } michael@0: michael@0: nsCSSOffsetState(nsIFrame *aFrame, nsRenderingContext *aRenderingContext, michael@0: nscoord aContainingBlockWidth); michael@0: michael@0: #ifdef DEBUG michael@0: // Reflow trace methods. Defined in nsFrame.cpp so they have access michael@0: // to the display-reflow infrastructure. michael@0: static void* DisplayInitOffsetsEnter(nsIFrame* aFrame, michael@0: nsCSSOffsetState* aState, michael@0: nscoord aHorizontalPercentBasis, michael@0: nscoord aVerticalPercentBasis, michael@0: const nsMargin* aBorder, michael@0: const nsMargin* aPadding); michael@0: static void DisplayInitOffsetsExit(nsIFrame* aFrame, michael@0: nsCSSOffsetState* aState, michael@0: void* aValue); michael@0: #endif michael@0: michael@0: private: michael@0: /** michael@0: * Computes margin values from the specified margin style information, and michael@0: * fills in the mComputedMargin member. michael@0: * michael@0: * @param aHorizontalPercentBasis michael@0: * Length to use for resolving percentage margin values in the horizontal michael@0: * axis. Usually the containing block width. michael@0: * @param aVerticalPercentBasis michael@0: * Length to use for resolving percentage margin values in the vertical michael@0: * axis. Usually the containing block width, per CSS21 sec 8.3, but may michael@0: * be the containing block *height*, e.g. in CSS3 Flexbox and Grid. michael@0: * @return true if the margin is dependent on the containing block size. michael@0: */ michael@0: bool ComputeMargin(nscoord aHorizontalPercentBasis, michael@0: nscoord aVerticalPercentBasis); michael@0: michael@0: /** michael@0: * Computes padding values from the specified padding style information, and michael@0: * fills in the mComputedPadding member. michael@0: * michael@0: * @param aHorizontalPercentBasis michael@0: * Length to use for resolving percentage padding values in the horizontal michael@0: * axis. Usually the containing block width. michael@0: * @param aVerticalPercentBasis michael@0: * Length to use for resolving percentage padding values in the vertical michael@0: * axis. Usually the containing block width, per CSS21 sec 8.4, but may michael@0: * be the containing block *height* in e.g. CSS3 Flexbox and Grid. michael@0: * @return true if the padding is dependent on the containing block size. michael@0: */ michael@0: bool ComputePadding(nscoord aHorizontalPercentBasis, michael@0: nscoord aVerticalPercentBasis, nsIAtom* aFrameType); michael@0: michael@0: protected: michael@0: michael@0: void InitOffsets(nscoord aHorizontalPercentBasis, michael@0: nscoord aVerticalPercentBasis, michael@0: nsIAtom* aFrameType, michael@0: const nsMargin *aBorder = nullptr, michael@0: const nsMargin *aPadding = nullptr); michael@0: michael@0: /* michael@0: * Convert nsStyleCoord to nscoord when percentages depend on the michael@0: * containing block width, and enumerated values are for width, michael@0: * min-width, or max-width. Does not handle auto widths. michael@0: */ michael@0: inline nscoord ComputeWidthValue(nscoord aContainingBlockWidth, michael@0: nscoord aContentEdgeToBoxSizing, michael@0: nscoord aBoxSizingToMarginEdge, michael@0: const nsStyleCoord& aCoord); michael@0: // same as previous, but using mComputedBorderPadding, mComputedPadding, michael@0: // and mComputedMargin michael@0: nscoord ComputeWidthValue(nscoord aContainingBlockWidth, michael@0: uint8_t aBoxSizing, michael@0: const nsStyleCoord& aCoord); michael@0: michael@0: nscoord ComputeHeightValue(nscoord aContainingBlockHeight, michael@0: uint8_t aBoxSizing, michael@0: const nsStyleCoord& aCoord); michael@0: }; michael@0: michael@0: /** michael@0: * State passed to a frame during reflow or intrinsic size calculation. michael@0: * michael@0: * XXX Refactor so only a base class (nsSizingState?) is used for intrinsic michael@0: * size calculation. michael@0: * michael@0: * @see nsIFrame#Reflow() michael@0: */ michael@0: struct nsHTMLReflowState : public nsCSSOffsetState { michael@0: // the reflow states are linked together. this is the pointer to the michael@0: // parent's reflow state michael@0: const nsHTMLReflowState* parentReflowState; michael@0: michael@0: // pointer to the float manager associated with this area michael@0: nsFloatManager* mFloatManager; michael@0: michael@0: // LineLayout object (only for inline reflow; set to nullptr otherwise) michael@0: nsLineLayout* mLineLayout; michael@0: michael@0: // The appropriate reflow state for the containing block (for michael@0: // percentage widths, etc.) of this reflow state's frame. michael@0: const nsHTMLReflowState *mCBReflowState; michael@0: michael@0: // The type of frame, from css's perspective. This value is michael@0: // initialized by the Init method below. michael@0: nsCSSFrameType mFrameType; michael@0: michael@0: // The amount the in-flow position of the block is moving vertically relative michael@0: // to its previous in-flow position (i.e. the amount the line containing the michael@0: // block is moving). michael@0: // This should be zero for anything which is not a block outside, and it michael@0: // should be zero for anything which has a non-block parent. michael@0: // The intended use of this value is to allow the accurate determination michael@0: // of the potential impact of a float michael@0: // This takes on an arbitrary value the first time a block is reflowed michael@0: nscoord mBlockDelta; michael@0: michael@0: // Accessors for the private fields below. Forcing all callers to use these michael@0: // will allow us to introduce logical-coordinate versions and gradually michael@0: // change clients from physical to logical as needed; and potentially switch michael@0: // the internal fields from physical to logical coordinates in due course, michael@0: // while maintaining compatibility with not-yet-updated code. michael@0: nscoord AvailableWidth() const { return mAvailableWidth; } michael@0: nscoord AvailableHeight() const { return mAvailableHeight; } michael@0: nscoord ComputedWidth() const { return mComputedWidth; } michael@0: nscoord ComputedHeight() const { return mComputedHeight; } michael@0: nscoord ComputedMinWidth() const { return mComputedMinWidth; } michael@0: nscoord ComputedMaxWidth() const { return mComputedMaxWidth; } michael@0: nscoord ComputedMinHeight() const { return mComputedMinHeight; } michael@0: nscoord ComputedMaxHeight() const { return mComputedMaxHeight; } michael@0: michael@0: nscoord& AvailableWidth() { return mAvailableWidth; } michael@0: nscoord& AvailableHeight() { return mAvailableHeight; } michael@0: nscoord& ComputedWidth() { return mComputedWidth; } michael@0: nscoord& ComputedHeight() { return mComputedHeight; } michael@0: nscoord& ComputedMinWidth() { return mComputedMinWidth; } michael@0: nscoord& ComputedMaxWidth() { return mComputedMaxWidth; } michael@0: nscoord& ComputedMinHeight() { return mComputedMinHeight; } michael@0: nscoord& ComputedMaxHeight() { return mComputedMaxHeight; } michael@0: michael@0: // ISize and BSize are logical-coordinate dimensions: michael@0: // ISize is the size in the writing mode's inline direction (which equates to michael@0: // width in horizontal writing modes, height in vertical ones), and BSize is michael@0: // the size in the block-progression direction. michael@0: nscoord AvailableISize() const michael@0: { return mWritingMode.IsVertical() ? mAvailableHeight : mAvailableWidth; } michael@0: nscoord AvailableBSize() const michael@0: { return mWritingMode.IsVertical() ? mAvailableWidth : mAvailableHeight; } michael@0: nscoord ComputedISize() const michael@0: { return mWritingMode.IsVertical() ? mComputedHeight : mComputedWidth; } michael@0: nscoord ComputedBSize() const michael@0: { return mWritingMode.IsVertical() ? mComputedWidth : mComputedHeight; } michael@0: nscoord ComputedMinISize() const michael@0: { return mWritingMode.IsVertical() ? mComputedMinHeight : mComputedMinWidth; } michael@0: nscoord ComputedMaxISize() const michael@0: { return mWritingMode.IsVertical() ? mComputedMaxHeight : mComputedMaxWidth; } michael@0: nscoord ComputedMinBSize() const michael@0: { return mWritingMode.IsVertical() ? mComputedMinWidth : mComputedMinHeight; } michael@0: nscoord ComputedMaxBSize() const michael@0: { return mWritingMode.IsVertical() ? mComputedMaxWidth : mComputedMaxHeight; } michael@0: michael@0: nscoord& AvailableISize() michael@0: { return mWritingMode.IsVertical() ? mAvailableHeight : mAvailableWidth; } michael@0: nscoord& AvailableBSize() michael@0: { return mWritingMode.IsVertical() ? mAvailableWidth : mAvailableHeight; } michael@0: nscoord& ComputedISize() michael@0: { return mWritingMode.IsVertical() ? mComputedHeight : mComputedWidth; } michael@0: nscoord& ComputedBSize() michael@0: { return mWritingMode.IsVertical() ? mComputedWidth : mComputedHeight; } michael@0: nscoord& ComputedMinISize() michael@0: { return mWritingMode.IsVertical() ? mComputedMinHeight : mComputedMinWidth; } michael@0: nscoord& ComputedMaxISize() michael@0: { return mWritingMode.IsVertical() ? mComputedMaxHeight : mComputedMaxWidth; } michael@0: nscoord& ComputedMinBSize() michael@0: { return mWritingMode.IsVertical() ? mComputedMinWidth : mComputedMinHeight; } michael@0: nscoord& ComputedMaxBSize() michael@0: { return mWritingMode.IsVertical() ? mComputedMaxWidth : mComputedMaxHeight; } michael@0: michael@0: // XXX this will need to change when we make mComputedOffsets logical; michael@0: // we won't be able to return a reference for the physical offsets michael@0: const nsMargin& ComputedPhysicalOffsets() const { return mComputedOffsets; } michael@0: nsMargin& ComputedPhysicalOffsets() { return mComputedOffsets; } michael@0: michael@0: LogicalMargin ComputedLogicalOffsets() const michael@0: { return LogicalMargin(mWritingMode, mComputedOffsets); } michael@0: michael@0: private: michael@0: // the available width in which to reflow the frame. The space michael@0: // represents the amount of room for the frame's margin, border, michael@0: // padding, and content area. The frame size you choose should fit michael@0: // within the available width. michael@0: nscoord mAvailableWidth; michael@0: michael@0: // A value of NS_UNCONSTRAINEDSIZE for the available height means michael@0: // you can choose whatever size you want. In galley mode the michael@0: // available height is always NS_UNCONSTRAINEDSIZE, and only page michael@0: // mode or multi-column layout involves a constrained height. The michael@0: // element's the top border and padding, and content, must fit. If the michael@0: // element is complete after reflow then its bottom border, padding michael@0: // and margin (and similar for its complete ancestors) will need to michael@0: // fit in this height. michael@0: nscoord mAvailableHeight; michael@0: michael@0: // The computed width specifies the frame's content area width, and it does michael@0: // not apply to inline non-replaced elements michael@0: // michael@0: // For replaced inline frames, a value of NS_INTRINSICSIZE means you should michael@0: // use your intrinsic width as the computed width michael@0: // michael@0: // For block-level frames, the computed width is based on the width of the michael@0: // containing block, the margin/border/padding areas, and the min/max width. michael@0: nscoord mComputedWidth; michael@0: michael@0: // The computed height specifies the frame's content height, and it does michael@0: // not apply to inline non-replaced elements michael@0: // michael@0: // For replaced inline frames, a value of NS_INTRINSICSIZE means you should michael@0: // use your intrinsic height as the computed height michael@0: // michael@0: // For non-replaced block-level frames in the flow and floated, a value of michael@0: // NS_AUTOHEIGHT means you choose a height to shrink wrap around the normal michael@0: // flow child frames. The height must be within the limit of the min/max michael@0: // height if there is such a limit michael@0: // michael@0: // For replaced block-level frames, a value of NS_INTRINSICSIZE michael@0: // means you use your intrinsic height as the computed height michael@0: nscoord mComputedHeight; michael@0: michael@0: // Computed values for 'left/top/right/bottom' offsets. Only applies to michael@0: // 'positioned' elements. These are PHYSICAL coordinates (for now). michael@0: nsMargin mComputedOffsets; michael@0: michael@0: // Computed values for 'min-width/max-width' and 'min-height/max-height' michael@0: // XXXldb The width ones here should go; they should be needed only michael@0: // internally. michael@0: nscoord mComputedMinWidth, mComputedMaxWidth; michael@0: nscoord mComputedMinHeight, mComputedMaxHeight; michael@0: michael@0: public: michael@0: // Cached pointers to the various style structs used during intialization michael@0: const nsStyleDisplay* mStyleDisplay; michael@0: const nsStyleVisibility* mStyleVisibility; michael@0: const nsStylePosition* mStylePosition; michael@0: const nsStyleBorder* mStyleBorder; michael@0: const nsStyleMargin* mStyleMargin; michael@0: const nsStylePadding* mStylePadding; michael@0: const nsStyleText* mStyleText; michael@0: michael@0: bool IsFloating() const; michael@0: michael@0: uint8_t GetDisplay() const; michael@0: michael@0: // a frame (e.g. nsTableCellFrame) which may need to generate a special michael@0: // reflow for percent height calculations michael@0: nsIPercentHeightObserver* mPercentHeightObserver; michael@0: michael@0: // CSS margin collapsing sometimes requires us to reflow michael@0: // optimistically assuming that margins collapse to see if clearance michael@0: // is required. When we discover that clearance is required, we michael@0: // store the frame in which clearance was discovered to the location michael@0: // requested here. michael@0: nsIFrame** mDiscoveredClearance; michael@0: michael@0: // This value keeps track of how deeply nested a given reflow state michael@0: // is from the top of the frame tree. michael@0: int16_t mReflowDepth; michael@0: michael@0: struct ReflowStateFlags { michael@0: uint16_t mSpecialHeightReflow:1; // used by tables to communicate special reflow (in process) to handle michael@0: // percent height frames inside cells which may not have computed heights michael@0: uint16_t mNextInFlowUntouched:1; // nothing in the frame's next-in-flow (or its descendants) michael@0: // is changing michael@0: uint16_t mIsTopOfPage:1; // Is the current context at the top of a michael@0: // page? When true, we force something michael@0: // that's too tall for a page/column to michael@0: // fit anyway to avoid infinite loops. michael@0: uint16_t mHasClearance:1; // Block has clearance michael@0: uint16_t mAssumingHScrollbar:1; // parent frame is an nsIScrollableFrame and it michael@0: // is assuming a horizontal scrollbar michael@0: uint16_t mAssumingVScrollbar:1; // parent frame is an nsIScrollableFrame and it michael@0: // is assuming a vertical scrollbar michael@0: michael@0: uint16_t mHResize:1; // Is frame (a) not dirty and (b) a michael@0: // different width than before? michael@0: michael@0: uint16_t mVResize:1; // Is frame (a) not dirty and (b) a michael@0: // different height than before or michael@0: // (potentially) in a context where michael@0: // percent heights have a different michael@0: // basis? michael@0: uint16_t mTableIsSplittable:1; // tables are splittable, this should happen only inside a page michael@0: // and never insider a column frame michael@0: uint16_t mHeightDependsOnAncestorCell:1; // Does frame height depend on michael@0: // an ancestor table-cell? michael@0: uint16_t mIsColumnBalancing:1; // nsColumnSetFrame is balancing columns michael@0: uint16_t mIsFlexContainerMeasuringHeight:1; // nsFlexContainerFrame is michael@0: // reflowing this child to michael@0: // measure its intrinsic height. michael@0: uint16_t mDummyParentReflowState:1; // a "fake" reflow state made michael@0: // in order to be the parent michael@0: // of a real one michael@0: uint16_t mMustReflowPlaceholders:1; // Should this frame reflow its place- michael@0: // holder children? If the available michael@0: // height of this frame didn't change, michael@0: // but its in a paginated environment michael@0: // (e.g. columns), it should always michael@0: // reflow its placeholder children. michael@0: } mFlags; michael@0: michael@0: // Note: The copy constructor is written by the compiler automatically. You michael@0: // can use that and then override specific values if you want, or you can michael@0: // call Init as desired... michael@0: michael@0: /** michael@0: * Initialize a ROOT reflow state. michael@0: * michael@0: * @param aPresContext Must be equal to aFrame->PresContext(). michael@0: * @param aFrame The frame for whose reflow state is being constructed. michael@0: * @param aRenderingContext The rendering context to be used for measurements. michael@0: * @param aAvailableSpace See comments for availableHeight and availableWidth michael@0: * members. michael@0: * @param aFlags A set of flags used for additional boolean parameters (see michael@0: * below). michael@0: */ michael@0: nsHTMLReflowState(nsPresContext* aPresContext, michael@0: nsIFrame* aFrame, michael@0: nsRenderingContext* aRenderingContext, michael@0: const nsSize& aAvailableSpace, michael@0: uint32_t aFlags = 0); michael@0: michael@0: /** michael@0: * Initialize a reflow state for a child frame's reflow. Some parts of the michael@0: * state are copied from the parent's reflow state. The remainder is computed. michael@0: * michael@0: * @param aPresContext Must be equal to aFrame->PresContext(). michael@0: * @param aParentReflowState A reference to an nsHTMLReflowState object that michael@0: * is to be the parent of this object. michael@0: * @param aFrame The frame for whose reflow state is being constructed. michael@0: * @param aAvailableSpace See comments for availableHeight and availableWidth michael@0: * members. michael@0: * @param aContainingBlockWidth An optional width, in app units, that is used michael@0: * by absolute positioning code to override default containing block michael@0: * width. michael@0: * @param aContainingBlockHeight An optional height, in app units, that is michael@0: * used by absolute positioning code to override default containing michael@0: * block height. michael@0: * @param aFlags A set of flags used for additional boolean parameters (see michael@0: * below). michael@0: */ michael@0: nsHTMLReflowState(nsPresContext* aPresContext, michael@0: const nsHTMLReflowState& aParentReflowState, michael@0: nsIFrame* aFrame, michael@0: const nsSize& aAvailableSpace, michael@0: nscoord aContainingBlockWidth = -1, michael@0: nscoord aContainingBlockHeight = -1, michael@0: uint32_t aFlags = 0); michael@0: michael@0: // Values for |aFlags| passed to constructor michael@0: enum { michael@0: // Indicates that the parent of this reflow state is "fake" (see michael@0: // mDummyParentReflowState in mFlags). michael@0: DUMMY_PARENT_REFLOW_STATE = (1<<0), michael@0: michael@0: // Indicates that the calling function will initialize the reflow state, and michael@0: // that the constructor should not call Init(). michael@0: CALLER_WILL_INIT = (1<<1) michael@0: }; michael@0: michael@0: // This method initializes various data members. It is automatically michael@0: // called by the various constructors michael@0: void Init(nsPresContext* aPresContext, michael@0: nscoord aContainingBlockWidth = -1, michael@0: nscoord aContainingBlockHeight = -1, michael@0: const nsMargin* aBorder = nullptr, michael@0: const nsMargin* aPadding = nullptr); michael@0: /** michael@0: * Find the content width of the containing block of aReflowState michael@0: */ michael@0: static nscoord michael@0: GetContainingBlockContentWidth(const nsHTMLReflowState* aReflowState); michael@0: michael@0: /** michael@0: * Calculate the used line-height property. The return value will be >= 0. michael@0: */ michael@0: nscoord CalcLineHeight() const; michael@0: michael@0: /** michael@0: * Same as CalcLineHeight() above, but doesn't need a reflow state. michael@0: * michael@0: * @param aBlockHeight The computed height of the content rect of the block michael@0: * that the line should fill. michael@0: * Only used with line-height:-moz-block-height. michael@0: * NS_AUTOHEIGHT results in a normal line-height for michael@0: * line-height:-moz-block-height. michael@0: * @param aFontSizeInflation The result of the appropriate michael@0: * nsLayoutUtils::FontSizeInflationFor call, michael@0: * or 1.0 if during intrinsic size michael@0: * calculation. michael@0: */ michael@0: static nscoord CalcLineHeight(nsIContent* aContent, michael@0: nsStyleContext* aStyleContext, michael@0: nscoord aBlockHeight, michael@0: float aFontSizeInflation); michael@0: michael@0: michael@0: void ComputeContainingBlockRectangle(nsPresContext* aPresContext, michael@0: const nsHTMLReflowState* aContainingBlockRS, michael@0: nscoord& aContainingBlockWidth, michael@0: nscoord& aContainingBlockHeight); michael@0: michael@0: /** michael@0: * Apply the mComputed(Min/Max)Width constraints to the content michael@0: * size computed so far. michael@0: */ michael@0: nscoord ApplyMinMaxWidth(nscoord aWidth) const { michael@0: if (NS_UNCONSTRAINEDSIZE != ComputedMaxWidth()) { michael@0: aWidth = std::min(aWidth, ComputedMaxWidth()); michael@0: } michael@0: return std::max(aWidth, ComputedMinWidth()); michael@0: } michael@0: michael@0: /** michael@0: * Apply the mComputed(Min/Max)Height constraints to the content michael@0: * size computed so far. michael@0: * michael@0: * @param aHeight The height that we've computed an to which we want to apply michael@0: * min/max constraints. michael@0: * @param aConsumed The amount of the computed height that was consumed by michael@0: * our prev-in-flows. michael@0: */ michael@0: nscoord ApplyMinMaxHeight(nscoord aHeight, nscoord aConsumed = 0) const { michael@0: aHeight += aConsumed; michael@0: michael@0: if (NS_UNCONSTRAINEDSIZE != ComputedMaxHeight()) { michael@0: aHeight = std::min(aHeight, ComputedMaxHeight()); michael@0: } michael@0: michael@0: if (NS_UNCONSTRAINEDSIZE != ComputedMinHeight()) { michael@0: aHeight = std::max(aHeight, ComputedMinHeight()); michael@0: } michael@0: michael@0: return aHeight - aConsumed; michael@0: } michael@0: michael@0: bool ShouldReflowAllKids() const { michael@0: // Note that we could make a stronger optimization for mVResize if michael@0: // we use it in a ShouldReflowChild test that replaces the current michael@0: // checks of NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN, if it michael@0: // were tested there along with NS_FRAME_CONTAINS_RELATIVE_HEIGHT. michael@0: // This would need to be combined with a slight change in which michael@0: // frames NS_FRAME_CONTAINS_RELATIVE_HEIGHT is marked on. michael@0: return (frame->GetStateBits() & NS_FRAME_IS_DIRTY) || michael@0: mFlags.mHResize || michael@0: (mFlags.mVResize && michael@0: (frame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)); michael@0: } michael@0: michael@0: // This method doesn't apply min/max computed widths to the value passed in. michael@0: void SetComputedWidth(nscoord aComputedWidth); michael@0: michael@0: // This method doesn't apply min/max computed heights to the value passed in. michael@0: void SetComputedHeight(nscoord aComputedHeight); michael@0: michael@0: void SetComputedHeightWithoutResettingResizeFlags(nscoord aComputedHeight) { michael@0: // Viewport frames reset the computed height on a copy of their reflow michael@0: // state when reflowing fixed-pos kids. In that case we actually don't michael@0: // want to mess with the resize flags, because comparing the frame's rect michael@0: // to the munged computed width is pointless. michael@0: ComputedHeight() = aComputedHeight; michael@0: } michael@0: michael@0: void SetTruncated(const nsHTMLReflowMetrics& aMetrics, nsReflowStatus* aStatus) const; michael@0: michael@0: bool WillReflowAgainForClearance() const { michael@0: return mDiscoveredClearance && *mDiscoveredClearance; michael@0: } michael@0: michael@0: // Compute the offsets for a relative position element michael@0: static void ComputeRelativeOffsets(uint8_t aCBDirection, michael@0: nsIFrame* aFrame, michael@0: nscoord aContainingBlockWidth, michael@0: nscoord aContainingBlockHeight, michael@0: nsMargin& aComputedOffsets); michael@0: michael@0: // If a relatively positioned element, adjust the position appropriately. michael@0: static void ApplyRelativePositioning(nsIFrame* aFrame, michael@0: const nsMargin& aComputedOffsets, michael@0: nsPoint* aPosition); michael@0: michael@0: void ApplyRelativePositioning(nsPoint* aPosition) const { michael@0: ApplyRelativePositioning(frame, ComputedPhysicalOffsets(), aPosition); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: // Reflow trace methods. Defined in nsFrame.cpp so they have access michael@0: // to the display-reflow infrastructure. michael@0: static void* DisplayInitConstraintsEnter(nsIFrame* aFrame, michael@0: nsHTMLReflowState* aState, michael@0: nscoord aCBWidth, michael@0: nscoord aCBHeight, michael@0: const nsMargin* aBorder, michael@0: const nsMargin* aPadding); michael@0: static void DisplayInitConstraintsExit(nsIFrame* aFrame, michael@0: nsHTMLReflowState* aState, michael@0: void* aValue); michael@0: static void* DisplayInitFrameTypeEnter(nsIFrame* aFrame, michael@0: nsHTMLReflowState* aState); michael@0: static void DisplayInitFrameTypeExit(nsIFrame* aFrame, michael@0: nsHTMLReflowState* aState, michael@0: void* aValue); michael@0: #endif michael@0: michael@0: protected: michael@0: void InitFrameType(nsIAtom* aFrameType); michael@0: void InitCBReflowState(); michael@0: void InitResizeFlags(nsPresContext* aPresContext, nsIAtom* aFrameType); michael@0: michael@0: void InitConstraints(nsPresContext* aPresContext, michael@0: nscoord aContainingBlockWidth, michael@0: nscoord aContainingBlockHeight, michael@0: const nsMargin* aBorder, michael@0: const nsMargin* aPadding, michael@0: nsIAtom* aFrameType); michael@0: michael@0: // Returns the nearest containing block or block frame (whether or not michael@0: // it is a containing block) for the specified frame. Also returns michael@0: // the left edge and width of the containing block's content area. michael@0: // These are returned in the coordinate space of the containing block. michael@0: nsIFrame* GetHypotheticalBoxContainer(nsIFrame* aFrame, michael@0: nscoord& aCBLeftEdge, michael@0: nscoord& aCBWidth); michael@0: michael@0: void CalculateHypotheticalBox(nsPresContext* aPresContext, michael@0: nsIFrame* aPlaceholderFrame, michael@0: nsIFrame* aContainingBlock, michael@0: nscoord aBlockLeftContentEdge, michael@0: nscoord aBlockContentWidth, michael@0: const nsHTMLReflowState* cbrs, michael@0: nsHypotheticalBox& aHypotheticalBox, michael@0: nsIAtom* aFrameType); michael@0: michael@0: void InitAbsoluteConstraints(nsPresContext* aPresContext, michael@0: const nsHTMLReflowState* cbrs, michael@0: nscoord aContainingBlockWidth, michael@0: nscoord aContainingBlockHeight, michael@0: nsIAtom* aFrameType); michael@0: michael@0: // Calculates the computed values for the 'min-Width', 'max-Width', michael@0: // 'min-Height', and 'max-Height' properties, and stores them in the assorted michael@0: // data members michael@0: void ComputeMinMaxValues(nscoord aContainingBlockWidth, michael@0: nscoord aContainingBlockHeight, michael@0: const nsHTMLReflowState* aContainingBlockRS); michael@0: michael@0: void CalculateHorizBorderPaddingMargin(nscoord aContainingBlockWidth, michael@0: nscoord* aInsideBoxSizing, michael@0: nscoord* aOutsideBoxSizing); michael@0: michael@0: void CalculateBlockSideMargins(nscoord aAvailWidth, michael@0: nscoord aComputedWidth, michael@0: nsIAtom* aFrameType); michael@0: }; michael@0: michael@0: #endif /* nsHTMLReflowState_h___ */ michael@0: