зеркало из https://github.com/mozilla/pjs.git
Bug 209694. Major rework of margin-collapsing and clearance to match CSS 2.1 rules. Also includes major incremental reflow fixes for those situations. See the bug for details. rubber-stamp r+sr=dbaron
This commit is contained in:
Родитель
fc246c8217
Коммит
fcfeb6506e
|
@ -434,3 +434,33 @@ nsLayoutUtils::GetNearestScrollingView(nsIView* aView, Direction aDirection)
|
|||
}
|
||||
return scrollableView;
|
||||
}
|
||||
|
||||
// Combine aNewBreakType with aOrigBreakType, but limit the break types
|
||||
// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT.
|
||||
PRUint8
|
||||
nsLayoutUtils::CombineBreakType(PRUint8 aOrigBreakType,
|
||||
PRUint8 aNewBreakType)
|
||||
{
|
||||
PRUint8 breakType = aOrigBreakType;
|
||||
switch(breakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
if ((NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
||||
breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
||||
breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_CLEAR_NONE:
|
||||
if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
||||
breakType = aNewBreakType;
|
||||
}
|
||||
}
|
||||
return breakType;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,10 @@ public:
|
|||
* otherwise return nsnull.
|
||||
*/
|
||||
static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPossiblePlaceholder);
|
||||
|
||||
// Combine aNewBreakType with aOrigBreakType, but limit the break types
|
||||
// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT.
|
||||
static PRUint8 CombineBreakType(PRUint8 aOrigBreakType, PRUint8 aNewBreakType);
|
||||
};
|
||||
|
||||
#endif // nsLayoutUtils_h__
|
||||
|
|
|
@ -1,458 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#ifndef nsHTMLReflowState_h___
|
||||
#define nsHTMLReflowState_h___
|
||||
|
||||
#include "nsMargin.h"
|
||||
#include "nsStyleCoord.h"
|
||||
|
||||
class nsIFrame;
|
||||
class nsPresContext;
|
||||
class nsReflowPath;
|
||||
class nsIRenderingContext;
|
||||
class nsSpaceManager;
|
||||
class nsLineLayout;
|
||||
class nsIPercentHeightObserver;
|
||||
|
||||
struct nsStyleDisplay;
|
||||
struct nsStyleVisibility;
|
||||
struct nsStylePosition;
|
||||
struct nsStyleBorder;
|
||||
struct nsStyleMargin;
|
||||
struct nsStylePadding;
|
||||
struct nsStyleText;
|
||||
struct nsHypotheticalBox;
|
||||
|
||||
/**
|
||||
* Constant used to indicate an unconstrained size.
|
||||
*
|
||||
* @see #Reflow()
|
||||
*/
|
||||
#define NS_UNCONSTRAINEDSIZE NS_MAXSIZE
|
||||
|
||||
/**
|
||||
* The reason the frame is being reflowed.
|
||||
*
|
||||
* XXX Should probably be a #define so it can be extended for specialized
|
||||
* reflow interfaces...
|
||||
*
|
||||
* @see nsHTMLReflowState
|
||||
*/
|
||||
enum nsReflowReason {
|
||||
eReflowReason_Initial = 0, // initial reflow of a newly created frame
|
||||
eReflowReason_Incremental = 1, // an incremental change has occured. see the reflow command for details
|
||||
eReflowReason_Resize = 2, // general request to determine a desired size
|
||||
eReflowReason_StyleChange = 3, // request to reflow because of a style change. Note: you must reflow
|
||||
// all your child frames
|
||||
eReflowReason_Dirty = 4 // request to reflow because you and/or your children are dirty
|
||||
};
|
||||
|
||||
/**
|
||||
* CSS Frame type. Included as part of the reflow state.
|
||||
*/
|
||||
typedef PRUint32 nsCSSFrameType;
|
||||
|
||||
#define NS_CSS_FRAME_TYPE_UNKNOWN 0
|
||||
#define NS_CSS_FRAME_TYPE_INLINE 1
|
||||
#define NS_CSS_FRAME_TYPE_BLOCK 2 /* block-level in normal flow */
|
||||
#define NS_CSS_FRAME_TYPE_FLOATING 3
|
||||
#define NS_CSS_FRAME_TYPE_ABSOLUTE 4
|
||||
#define NS_CSS_FRAME_TYPE_INTERNAL_TABLE 5 /* row group frame, row frame, cell frame, ... */
|
||||
|
||||
/**
|
||||
* Bit-flag that indicates whether the element is replaced. Applies to inline,
|
||||
* block-level, floating, and absolutely positioned elements
|
||||
*/
|
||||
#define NS_CSS_FRAME_TYPE_REPLACED 0x8000
|
||||
|
||||
/**
|
||||
* Helper macros for telling whether items are replaced
|
||||
*/
|
||||
#define NS_FRAME_IS_REPLACED(_ft) \
|
||||
(NS_CSS_FRAME_TYPE_REPLACED == ((_ft) & NS_CSS_FRAME_TYPE_REPLACED))
|
||||
|
||||
#define NS_FRAME_REPLACED(_ft) \
|
||||
(NS_CSS_FRAME_TYPE_REPLACED | (_ft))
|
||||
|
||||
/**
|
||||
* A macro to extract the type. Masks off the 'replaced' bit-flag
|
||||
*/
|
||||
#define NS_FRAME_GET_TYPE(_ft) \
|
||||
((_ft) & ~NS_CSS_FRAME_TYPE_REPLACED)
|
||||
|
||||
#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE
|
||||
#define NS_SHRINKWRAPWIDTH NS_UNCONSTRAINEDSIZE
|
||||
#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE
|
||||
#define NS_AUTOMARGIN NS_UNCONSTRAINEDSIZE
|
||||
#define NS_AUTOOFFSET NS_UNCONSTRAINEDSIZE
|
||||
// NOTE: there are assumptions all over that these have the same value, namely NS_UNCONSTRAINEDSIZE
|
||||
// if any are changed to be a value other than NS_UNCONSTRAINEDSIZE
|
||||
// at least update AdjustComputedHeight/Width and test ad nauseum
|
||||
|
||||
/**
|
||||
* Reflow state passed to a frame during reflow.
|
||||
*
|
||||
* @see nsIFrame#Reflow()
|
||||
*/
|
||||
struct nsHTMLReflowState {
|
||||
// the reflow states are linked together. this is the pointer to the
|
||||
// parent's reflow state
|
||||
const nsHTMLReflowState* parentReflowState;
|
||||
|
||||
// the frame being reflowed
|
||||
nsIFrame* frame;
|
||||
|
||||
// the reason for the reflow
|
||||
nsReflowReason reason;
|
||||
|
||||
// the incremental reflow path, when the reflow reason is
|
||||
// eReflowReason_Incremental. Specifically, this corresponds to the
|
||||
// portion of the incremental reflow path from `frame' down. Note
|
||||
// that it is safe to assume that this is non-null: we maintain the
|
||||
// invariant that it contains a valid nsReflowPath pointer when
|
||||
// reason == eReflowReason_Incremental.
|
||||
nsReflowPath *path;
|
||||
|
||||
// the available space in which to reflow the frame. The space represents the
|
||||
// amount of room for the frame's border, padding, and content area (not the
|
||||
// margin area. The parent frame deals with the child frame's margins). The
|
||||
// frame size you choose should fit within the available space.
|
||||
// A value of NS_UNCONSTRAINEDSIZE for the available height means you can
|
||||
// choose whatever size you want. In galley mode the available height is always
|
||||
// NS_UNCONSTRAINEDSIZE, and only page mode involves a constrained height
|
||||
nscoord availableWidth, availableHeight;
|
||||
|
||||
// rendering context to use for measurement
|
||||
nsIRenderingContext* rendContext;
|
||||
|
||||
// The type of frame, from css's perspective. This value is
|
||||
// initialized by the Init method below.
|
||||
nsCSSFrameType mFrameType;
|
||||
|
||||
// pointer to the space manager associated with this area
|
||||
nsSpaceManager* mSpaceManager;
|
||||
|
||||
// LineLayout object (only for inline reflow; set to NULL otherwise)
|
||||
nsLineLayout* mLineLayout;
|
||||
|
||||
// The appropriate reflow state for the containing block (for
|
||||
// percentage widths, etc.) of this reflow state's frame.
|
||||
const nsHTMLReflowState *mCBReflowState;
|
||||
|
||||
// The computed width specifies the frame's content area width, and it does
|
||||
// not apply to inline non-replaced elements
|
||||
//
|
||||
// For replaced inline frames, a value of NS_INTRINSICSIZE means you should
|
||||
// use your intrinsic width as the computed width
|
||||
//
|
||||
// For block-level frames, the computed width is based on the width of the
|
||||
// containing block, the margin/border/padding areas, and the min/max width.
|
||||
// A value of NS_SHRINKWRAPWIDTH means that you should choose a width based
|
||||
// on your content. The width may be as large as the specified maximum width
|
||||
// (see mComputedMaxWidth).
|
||||
nscoord mComputedWidth;
|
||||
|
||||
// The computed height specifies the frame's content height, and it does
|
||||
// not apply to inline non-replaced elements
|
||||
//
|
||||
// For replaced inline frames, a value of NS_INTRINSICSIZE means you should
|
||||
// use your intrinsic height as the computed height
|
||||
//
|
||||
// For non-replaced block-level frames in the flow and floated, a value of
|
||||
// NS_AUTOHEIGHT means you choose a height to shrink wrap around the normal
|
||||
// flow child frames. The height must be within the limit of the min/max
|
||||
// height if there is such a limit
|
||||
//
|
||||
// For replaced block-level frames, a value of NS_INTRINSICSIZE
|
||||
// means you use your intrinsic height as the computed height
|
||||
nscoord mComputedHeight;
|
||||
|
||||
// Computed margin values
|
||||
nsMargin mComputedMargin;
|
||||
|
||||
// Cached copy of the border values
|
||||
nsMargin mComputedBorderPadding;
|
||||
|
||||
// Computed padding values
|
||||
nsMargin mComputedPadding;
|
||||
|
||||
// Computed values for 'left/top/right/bottom' offsets. Only applies to
|
||||
// 'positioned' elements
|
||||
nsMargin mComputedOffsets;
|
||||
|
||||
// Computed values for 'min-width/max-width' and 'min-height/max-height'
|
||||
nscoord mComputedMinWidth, mComputedMaxWidth;
|
||||
nscoord mComputedMinHeight, mComputedMaxHeight;
|
||||
|
||||
// Compact margin available space
|
||||
nscoord mCompactMarginWidth;
|
||||
|
||||
// Cached pointers to the various style structs used during intialization
|
||||
const nsStyleDisplay* mStyleDisplay;
|
||||
const nsStyleVisibility* mStyleVisibility;
|
||||
const nsStylePosition* mStylePosition;
|
||||
const nsStyleBorder* mStyleBorder;
|
||||
const nsStyleMargin* mStyleMargin;
|
||||
const nsStylePadding* mStylePadding;
|
||||
const nsStyleText* mStyleText;
|
||||
|
||||
// a frame (e.g. nsTableCellFrame) which may need to generate a special
|
||||
// reflow for percent height calculations
|
||||
nsIPercentHeightObserver* mPercentHeightObserver;
|
||||
|
||||
// a frame (e.g. nsTableFrame) which initiates a special reflow for percent height calculations
|
||||
nsIFrame* mPercentHeightReflowInitiator;
|
||||
|
||||
// This value keeps track of how deeply nested a given reflow state
|
||||
// is from the top of the frame tree.
|
||||
PRInt16 mReflowDepth;
|
||||
|
||||
struct ReflowStateFlags {
|
||||
PRUint16 mSpecialHeightReflow:1; // used by tables to communicate special reflow (in process) to handle
|
||||
// percent height frames inside cells which may not have computed heights
|
||||
PRUint16 mNextInFlowUntouched:1; // nothing in the frame's next-in-flow (or its descendants)
|
||||
// is changing
|
||||
PRUint16 mIsTopOfPage:1; // is the current context at the top of a page?
|
||||
PRUint16 mBlinks:1; // Keep track of text-decoration: blink
|
||||
PRUint16 mVisualBidiFormControl:1; // Keep track of descendants of form controls on Visual Bidi pages
|
||||
} mFlags;
|
||||
|
||||
#ifdef IBMBIDI
|
||||
nscoord mRightEdge;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
// hook for attaching debug info (e.g. tables may attach a timer during reflow)
|
||||
void* mDebugHook;
|
||||
|
||||
static const char* ReasonToString(nsReflowReason aReason);
|
||||
#endif
|
||||
|
||||
// Note: The copy constructor is written by the compiler automatically. You
|
||||
// can use that and then override specific values if you want, or you can
|
||||
// call Init as desired...
|
||||
|
||||
// Initialize a <b>root</b> reflow state with a rendering context to
|
||||
// use for measuring things.
|
||||
nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsReflowReason aReason,
|
||||
nsIRenderingContext* aRenderingContext,
|
||||
const nsSize& aAvailableSpace);
|
||||
|
||||
// Initialize a <b>root</b> reflow state for an <b>incremental</b>
|
||||
// reflow.
|
||||
nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsReflowPath* aReflowPath,
|
||||
nsIRenderingContext* aRenderingContext,
|
||||
const nsSize& aAvailableSpace);
|
||||
|
||||
// Initialize a reflow state for a child frames reflow. Some state
|
||||
// is copied from the parent reflow state; the remaining state is
|
||||
// computed.
|
||||
nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState& aParentReflowState,
|
||||
nsIFrame* aFrame,
|
||||
const nsSize& aAvailableSpace,
|
||||
nsReflowReason aReason,
|
||||
PRBool aInit = PR_TRUE);
|
||||
|
||||
// Same as the previous except that the reason is taken from the
|
||||
// parent's reflow state.
|
||||
nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState& aParentReflowState,
|
||||
nsIFrame* aFrame,
|
||||
const nsSize& aAvailableSpace);
|
||||
|
||||
// Used when you want to override the default containing block
|
||||
// width and height. Used by absolute positioning code
|
||||
nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState& aParentReflowState,
|
||||
nsIFrame* aFrame,
|
||||
const nsSize& aAvailableSpace,
|
||||
nscoord aContainingBlockWidth,
|
||||
nscoord aContainingBlockHeight,
|
||||
nsReflowReason aReason);
|
||||
|
||||
// This method initializes various data members. It is automatically
|
||||
// called by the various constructors
|
||||
void Init(nsPresContext* aPresContext,
|
||||
nscoord aContainingBlockWidth = -1,
|
||||
nscoord aContainingBlockHeight = -1,
|
||||
nsMargin* aBorder = nsnull,
|
||||
nsMargin* aPadding = nsnull);
|
||||
/**
|
||||
* Find the content width of the containing block of aReflowState
|
||||
*/
|
||||
static nscoord
|
||||
GetContainingBlockContentWidth(const nsHTMLReflowState* aReflowState);
|
||||
|
||||
/**
|
||||
* Find the containing block of aFrame. This may return null if
|
||||
* there isn't one (but that should really only happen for root
|
||||
* frames).
|
||||
*/
|
||||
static nsIFrame* GetContainingBlockFor(const nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Get the page box reflow state, starting from a frames
|
||||
* <B>parent</B> reflow state (the parent reflow state may or may not end
|
||||
* up being the containing block reflow state)
|
||||
*/
|
||||
static const nsHTMLReflowState*
|
||||
GetPageBoxReflowState(const nsHTMLReflowState* aParentRS);
|
||||
|
||||
/**
|
||||
* Compute the border plus padding for <TT>aFrame</TT>. If a
|
||||
* percentage needs to be computed it will be computed by finding
|
||||
* the containing block, use GetContainingBlockReflowState.
|
||||
* aParentReflowState is aFrame's
|
||||
* parent's reflow state. The resulting computed border plus padding
|
||||
* is returned in aResult.
|
||||
*/
|
||||
static void ComputeBorderPaddingFor(nsIFrame* aFrame,
|
||||
const nsHTMLReflowState* aParentRS,
|
||||
nsMargin& aResult);
|
||||
|
||||
/**
|
||||
* Calculate the raw line-height property for the given frame. The return
|
||||
* value, if line-height was applied and is valid will be >= 0. Otherwise,
|
||||
* the return value will be <0 which is illegal (CSS2 spec: section 10.8.1).
|
||||
*/
|
||||
static nscoord CalcLineHeight(nsPresContext* aPresContext,
|
||||
nsIRenderingContext* aRenderingContext,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
static PRBool UseComputedHeight();
|
||||
|
||||
void InitFrameType();
|
||||
|
||||
void ComputeContainingBlockRectangle(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState* aContainingBlockRS,
|
||||
nscoord& aContainingBlockWidth,
|
||||
nscoord& aContainingBlockHeight);
|
||||
|
||||
void CalculateBlockSideMargins(nscoord aAvailWidth,
|
||||
nscoord aComputedWidth);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void InitCBReflowState();
|
||||
|
||||
void InitConstraints(nsPresContext* aPresContext,
|
||||
nscoord aContainingBlockWidth,
|
||||
nscoord aContainingBlockHeight,
|
||||
nsMargin* aBorder,
|
||||
nsMargin* aPadding);
|
||||
|
||||
void CalculateHypotheticalBox(nsPresContext* aPresContext,
|
||||
nsIFrame* aPlaceholderFrame,
|
||||
nsIFrame* aBlockFrame,
|
||||
nsMargin& aBlockContentArea,
|
||||
const nsHTMLReflowState* cbrs,
|
||||
nsHypotheticalBox& aHypotheticalBox);
|
||||
|
||||
void InitAbsoluteConstraints(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState* cbrs,
|
||||
nscoord aContainingBlockWidth,
|
||||
nscoord aContainingBlockHeight);
|
||||
|
||||
void ComputeRelativeOffsets(const nsHTMLReflowState* cbrs,
|
||||
nscoord aContainingBlockWidth,
|
||||
nscoord aContainingBlockHeight);
|
||||
|
||||
void ComputeBlockBoxData(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState* cbrs,
|
||||
nsStyleUnit aWidthUnit,
|
||||
nsStyleUnit aHeightUnit,
|
||||
nscoord aContainingBlockWidth,
|
||||
nscoord aContainingBlockHeight);
|
||||
|
||||
void ComputeHorizontalValue(nscoord aContainingBlockWidth,
|
||||
nsStyleUnit aUnit,
|
||||
const nsStyleCoord& aCoord,
|
||||
nscoord& aResult);
|
||||
|
||||
void ComputeVerticalValue(nscoord aContainingBlockHeight,
|
||||
nsStyleUnit aUnit,
|
||||
const nsStyleCoord& aCoord,
|
||||
nscoord& aResult);
|
||||
|
||||
// Computes margin values from the specified margin style information, and
|
||||
// fills in the mComputedMargin member
|
||||
void ComputeMargin(nscoord aContainingBlockWidth,
|
||||
const nsHTMLReflowState* aContainingBlockRS);
|
||||
|
||||
// Computes padding values from the specified padding style information, and
|
||||
// fills in the mComputedPadding member
|
||||
void ComputePadding(nscoord aContainingBlockWidth,
|
||||
const nsHTMLReflowState* aContainingBlockRS);
|
||||
|
||||
// Calculates the computed values for the 'min-Width', 'max-Width',
|
||||
// 'min-Height', and 'max-Height' properties, and stores them in the assorted
|
||||
// data members
|
||||
void ComputeMinMaxValues(nscoord aContainingBlockWidth,
|
||||
nscoord aContainingBlockHeight,
|
||||
const nsHTMLReflowState* aContainingBlockRS);
|
||||
|
||||
nscoord CalculateHorizBorderPaddingMargin(nscoord aContainingBlockWidth);
|
||||
|
||||
// Adjust Computed sizes for Min/Max Width and box-Sizing (if
|
||||
// aAdjustForBoxSizing is true)
|
||||
// - guarantees that the computed height/width will be non-negative
|
||||
// If the value goes negative (because the padding or border is greater than
|
||||
// the width/height and it is removed due to box sizing) then it is driven to 0
|
||||
void AdjustComputedHeight(PRBool aAdjustForBoxSizing);
|
||||
void AdjustComputedWidth(PRBool aAdjustForBoxSizing);
|
||||
|
||||
#ifdef IBMBIDI
|
||||
/**
|
||||
* Test whether the frame is a form control in a visual Bidi page.
|
||||
* This is necessary for backwards-compatibility, because most visual
|
||||
* pages use logical order for form controls so that they will
|
||||
* display correctly on native widgets in OSs with Bidi support
|
||||
* @param aPresContext the pres context
|
||||
* @return whether the frame is a BIDI form control
|
||||
*/
|
||||
PRBool IsBidiFormControl(nsPresContext* aPresContext);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* nsHTMLReflowState_h___ */
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Boris Zbarsky <bzbarsky@mit.edu>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsLayoutUtils_h__
|
||||
#define nsLayoutUtils_h__
|
||||
|
||||
class nsIFrame;
|
||||
class nsPresContext;
|
||||
class nsIContent;
|
||||
class nsIAtom;
|
||||
class nsIScrollableView;
|
||||
class nsIScrollableFrame;
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsIView.h"
|
||||
|
||||
/**
|
||||
* nsLayoutUtils is a namespace class used for various helper
|
||||
* functions that are useful in multiple places in layout. The goal
|
||||
* is not to define multiple copies of the same static helper.
|
||||
*/
|
||||
class nsLayoutUtils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* GetBeforeFrame returns the :before frame of the given frame, if
|
||||
* one exists. This is typically O(1). The frame passed in must be
|
||||
* the first-in-flow.
|
||||
*
|
||||
* @param aFrame the frame whose :before is wanted
|
||||
* @param aPresContext the prescontext
|
||||
* @return the :before frame or nsnull if there isn't one
|
||||
*/
|
||||
static nsIFrame* GetBeforeFrame(nsIFrame* aFrame, nsPresContext* aPresContext);
|
||||
|
||||
/**
|
||||
* GetAfterFrame returns the :after frame of the given frame, if one
|
||||
* exists. This will walk the in-flow chain to the last-in-flow if
|
||||
* needed. This function is typically O(N) in the number of child
|
||||
* frames, following in-flows, etc.
|
||||
*
|
||||
* @param aFrame the frame whose :after is wanted
|
||||
* @param aPresContext the prescontext
|
||||
* @return the :after frame or nsnull if there isn't one
|
||||
*/
|
||||
static nsIFrame* GetAfterFrame(nsIFrame* aFrame, nsPresContext* aPresContext);
|
||||
|
||||
/**
|
||||
* Given a frame, search up the frame tree until we find an
|
||||
* ancestor "Page" frame, if any.
|
||||
*
|
||||
* @param the frame to start at
|
||||
* @return a frame of type nsLayoutAtoms::pageFrame or nsnull if no
|
||||
* such ancestor exists
|
||||
*/
|
||||
static nsIFrame* GetPageFrame(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* IsGeneratedContentFor returns PR_TRUE if aFrame is generated
|
||||
* content of type aPseudoElement for aContent
|
||||
*
|
||||
* @param aContent the content node we're looking at. If this is
|
||||
* null, then we just assume that aFrame has the right content
|
||||
* pointer.
|
||||
* @param aFrame the frame we're looking at
|
||||
* @param aPseudoElement the pseudo type we're interested in
|
||||
* @return whether aFrame is the generated aPseudoElement frame for aContent
|
||||
*/
|
||||
static PRBool IsGeneratedContentFor(nsIContent* aContent, nsIFrame* aFrame,
|
||||
nsIAtom* aPseudoElement);
|
||||
|
||||
/**
|
||||
* CompareTreePosition determines whether aContent1 comes before or
|
||||
* after aContent2 in a preorder traversal of the content tree.
|
||||
*
|
||||
* @param aCommonAncestor either null, or a common ancestor of
|
||||
* aContent1 and aContent2. Actually this is
|
||||
* only a hint; if it's not an ancestor of
|
||||
* aContent1 or aContent2, this function will
|
||||
* still work, but it will be slower than
|
||||
* normal.
|
||||
* @return < 0 if aContent1 is before aContent2
|
||||
* > 0 if aContent1 is after aContent2,
|
||||
* 0 otherwise (meaning they're the same, or they're in
|
||||
* different documents)
|
||||
*/
|
||||
static PRInt32 CompareTreePosition(nsIContent* aContent1,
|
||||
nsIContent* aContent2,
|
||||
nsIContent* aCommonAncestor = nsnull)
|
||||
{
|
||||
return DoCompareTreePosition(aContent1, aContent2, -1, 1, aCommonAncestor);
|
||||
}
|
||||
|
||||
/*
|
||||
* More generic version of |CompareTreePosition|. |aIf1Ancestor|
|
||||
* gives the value to return when 1 is an ancestor of 2, and likewise
|
||||
* for |aIf2Ancestor|. Passing (-1, 1) gives preorder traversal
|
||||
* order, and (1, -1) gives postorder traversal order.
|
||||
*/
|
||||
static PRInt32 DoCompareTreePosition(nsIContent* aContent1,
|
||||
nsIContent* aContent2,
|
||||
PRInt32 aIf1Ancestor,
|
||||
PRInt32 aIf2Ancestor,
|
||||
nsIContent* aCommonAncestor = nsnull);
|
||||
|
||||
/**
|
||||
* GetLastSibling simply finds the last sibling of aFrame, or returns nsnull if
|
||||
* aFrame is null.
|
||||
*/
|
||||
static nsIFrame* GetLastSibling(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* FindSiblingViewFor locates the child of aParentView that aFrame's
|
||||
* view should be inserted 'above' (i.e., before in sibling view
|
||||
* order). This is the first child view of aParentView whose
|
||||
* corresponding content is before aFrame's content (view siblings
|
||||
* are in reverse content order).
|
||||
*/
|
||||
static nsIView* FindSiblingViewFor(nsIView* aParentView, nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* IsProperAncestorFrame checks whether aAncestorFrame is an ancestor
|
||||
* of aFrame and not equal to aFrame.
|
||||
* @param aCommonAncestor nsnull, or a common ancestor of aFrame and
|
||||
* aAncestorFrame. If non-null, this can bound the search and speed up
|
||||
* the function
|
||||
*/
|
||||
static PRBool IsProperAncestorFrame(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
|
||||
nsIFrame* aCommonAncestor = nsnull);
|
||||
|
||||
/**
|
||||
* GetFrameFor returns the root frame for a view
|
||||
* @param aView is the view to return the root frame for
|
||||
* @return the root frame for the view
|
||||
*/
|
||||
static nsIFrame* GetFrameFor(nsIView *aView)
|
||||
{ return NS_STATIC_CAST(nsIFrame*, aView->GetClientData()); }
|
||||
|
||||
/**
|
||||
* GetScrollableFrameFor returns the scrollable frame for a scrollable view
|
||||
* @param aScrollableView is the scrollable view to return the
|
||||
* scrollable frame for.
|
||||
* @return the scrollable frame for the scrollable view
|
||||
*/
|
||||
static nsIScrollableFrame* GetScrollableFrameFor(nsIScrollableView *aScrollableView);
|
||||
|
||||
/**
|
||||
* GetScrollableFrameFor returns the scrollable frame for a scrolled frame
|
||||
*/
|
||||
static nsIScrollableFrame* GetScrollableFrameFor(nsIFrame *aScrolledFrame);
|
||||
|
||||
static nsPresContext::ScrollbarStyles
|
||||
ScrollbarStylesOfView(nsIScrollableView *aScrollableView);
|
||||
|
||||
/**
|
||||
* GetNearestScrollingView locates the first ancestor of aView (or
|
||||
* aView itself) that is scrollable. It does *not* count an
|
||||
* 'overflow' style of 'hidden' as scrollable, even though a scrolling
|
||||
* view is present. Thus, the direction of the scroll is needed as
|
||||
* an argument.
|
||||
*
|
||||
* @param aView the view we're looking at
|
||||
* @param aDirection Whether it's for horizontal or vertical scrolling.
|
||||
* @return the nearest scrollable view or nsnull if not found
|
||||
*/
|
||||
enum Direction { eHorizontal, eVertical, eEither };
|
||||
static nsIScrollableView* GetNearestScrollingView(nsIView* aView,
|
||||
Direction aDirection);
|
||||
|
||||
/**
|
||||
* HasPseudoStyle returns PR_TRUE if aContent (whose primary style
|
||||
* context is aStyleContext) has the aPseudoElement pseudo-style
|
||||
* attached to it; returns PR_FALSE otherwise.
|
||||
*
|
||||
* @param aContent the content node we're looking at
|
||||
* @param aStyleContext aContent's style context
|
||||
* @param aPseudoElement the name of the pseudo style we care about
|
||||
* @param aPresContext the presentation context
|
||||
* @return whether aContent has aPseudoElement style attached to it
|
||||
*/
|
||||
static PRBool HasPseudoStyle(nsIContent* aContent,
|
||||
nsStyleContext* aStyleContext,
|
||||
nsIAtom* aPseudoElement,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aPresContext, "Must have a prescontext");
|
||||
NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
|
||||
|
||||
nsRefPtr<nsStyleContext> pseudoContext;
|
||||
if (aContent) {
|
||||
pseudoContext = aPresContext->StyleSet()->
|
||||
ProbePseudoStyleFor(aContent, aPseudoElement, aStyleContext);
|
||||
}
|
||||
return pseudoContext != nsnull;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this frame is a placeholder for a float, then return the float,
|
||||
* otherwise return nsnull.
|
||||
*/
|
||||
static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPossiblePlaceholder);
|
||||
};
|
||||
|
||||
#endif // nsLayoutUtils_h__
|
|
@ -1,436 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsFrameList.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIScrollableView.h"
|
||||
#include "nsPlaceholderFrame.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
|
||||
/**
|
||||
* A namespace class for static layout utilities.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GetFirstChildFrame returns the first "real" child frame of a
|
||||
* given frame. It will descend down into pseudo-frames (unless the
|
||||
* pseudo-frame is the :before generated frame).
|
||||
* @param aPresContext the prescontext
|
||||
* @param aFrame the frame
|
||||
* @param aFrame the frame's content node
|
||||
*/
|
||||
static nsIFrame*
|
||||
GetFirstChildFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
// Get the first child frame
|
||||
nsIFrame* childFrame = aFrame->GetFirstChild(nsnull);
|
||||
|
||||
// If the child frame is a pseudo-frame, then return its first child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (childFrame &&
|
||||
childFrame->IsPseudoFrame(aContent) &&
|
||||
!childFrame->IsGeneratedContentFrame()) {
|
||||
return GetFirstChildFrame(aPresContext, childFrame, aContent);
|
||||
}
|
||||
|
||||
return childFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetLastChildFrame returns the last "real" child frame of a
|
||||
* given frame. It will descend down into pseudo-frames (unless the
|
||||
* pseudo-frame is the :after generated frame).
|
||||
* @param aPresContext the prescontext
|
||||
* @param aFrame the frame
|
||||
* @param aFrame the frame's content node
|
||||
*/
|
||||
static nsIFrame*
|
||||
GetLastChildFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
// Get the last in flow frame
|
||||
nsIFrame* lastInFlow = aFrame->GetLastInFlow();
|
||||
|
||||
// Get the last child frame
|
||||
nsIFrame* firstChildFrame = lastInFlow->GetFirstChild(nsnull);
|
||||
if (firstChildFrame) {
|
||||
nsFrameList frameList(firstChildFrame);
|
||||
nsIFrame* lastChildFrame = frameList.LastChild();
|
||||
|
||||
NS_ASSERTION(lastChildFrame, "unexpected error");
|
||||
|
||||
// Get the frame's first-in-flow. This matters in case the frame has
|
||||
// been continuted across multiple lines
|
||||
lastChildFrame = lastChildFrame->GetFirstInFlow();
|
||||
|
||||
// If the last child frame is a pseudo-frame, then return its last child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (lastChildFrame &&
|
||||
lastChildFrame->IsPseudoFrame(aContent) &&
|
||||
!lastChildFrame->IsGeneratedContentFrame()) {
|
||||
return GetLastChildFrame(aPresContext, lastChildFrame, aContent);
|
||||
}
|
||||
|
||||
return lastChildFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame, nsPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
NS_ASSERTION(!aFrame->GetPrevInFlow(), "aFrame must be first-in-flow");
|
||||
|
||||
nsIFrame* firstFrame = GetFirstChildFrame(aPresContext, aFrame, aFrame->GetContent());
|
||||
|
||||
if (firstFrame && IsGeneratedContentFor(nsnull, firstFrame,
|
||||
nsCSSPseudoElements::before)) {
|
||||
return firstFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame, nsPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
nsIFrame* lastFrame = GetLastChildFrame(aPresContext, aFrame, aFrame->GetContent());
|
||||
|
||||
if (lastFrame && IsGeneratedContentFor(nsnull, lastFrame,
|
||||
nsCSSPseudoElements::after)) {
|
||||
return lastFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetPageFrame(nsIFrame* aFrame)
|
||||
{
|
||||
for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
|
||||
if (frame->GetType() == nsLayoutAtoms::pageFrame) {
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
|
||||
if (nsLayoutAtoms::placeholderFrame != aFrame->GetType()) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIFrame *outOfFlowFrame =
|
||||
NS_STATIC_CAST(nsPlaceholderFrame*, aFrame)->GetOutOfFlowFrame();
|
||||
// This is a hack.
|
||||
if (outOfFlowFrame &&
|
||||
!outOfFlowFrame->GetStyleDisplay()->IsAbsolutelyPositioned()) {
|
||||
return outOfFlowFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// static
|
||||
PRBool
|
||||
nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent,
|
||||
nsIFrame* aFrame,
|
||||
nsIAtom* aPseudoElement)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Must have a frame");
|
||||
NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
|
||||
|
||||
if (!aFrame->IsGeneratedContentFrame()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (aContent && aFrame->GetContent() != aContent) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
return aFrame->GetStyleContext()->GetPseudoType() == aPseudoElement;
|
||||
}
|
||||
|
||||
// static
|
||||
PRBool
|
||||
nsLayoutUtils::IsProperAncestorFrame(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
|
||||
nsIFrame* aCommonAncestor)
|
||||
{
|
||||
if (aFrame == aCommonAncestor) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIFrame* parentFrame = aFrame->GetParent();
|
||||
|
||||
while (parentFrame != aCommonAncestor) {
|
||||
if (parentFrame == aAncestorFrame) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
parentFrame = parentFrame->GetParent();
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
PRInt32
|
||||
nsLayoutUtils::DoCompareTreePosition(nsIContent* aContent1,
|
||||
nsIContent* aContent2,
|
||||
PRInt32 aIf1Ancestor,
|
||||
PRInt32 aIf2Ancestor,
|
||||
nsIContent* aCommonAncestor)
|
||||
{
|
||||
NS_PRECONDITION(aContent1, "aContent1 must not be null");
|
||||
NS_PRECONDITION(aContent2, "aContent2 must not be null");
|
||||
|
||||
nsAutoVoidArray content1Ancestors;
|
||||
nsIContent* c1;
|
||||
for (c1 = aContent1; c1 && c1 != aCommonAncestor; c1 = c1->GetParent()) {
|
||||
content1Ancestors.AppendElement(c1);
|
||||
}
|
||||
if (!c1 && aCommonAncestor) {
|
||||
// So, it turns out aCommonAncestor was not an ancestor of c1. Oops.
|
||||
// Never mind. We can continue as if aCommonAncestor was null.
|
||||
aCommonAncestor = nsnull;
|
||||
}
|
||||
|
||||
nsAutoVoidArray content2Ancestors;
|
||||
nsIContent* c2;
|
||||
for (c2 = aContent2; c2 && c2 != aCommonAncestor; c2 = c2->GetParent()) {
|
||||
content2Ancestors.AppendElement(c2);
|
||||
}
|
||||
if (!c2 && aCommonAncestor) {
|
||||
// So, it turns out aCommonAncestor was not an ancestor of c2.
|
||||
// We need to retry with no common ancestor hint.
|
||||
return DoCompareTreePosition(aContent1, aContent2,
|
||||
aIf1Ancestor, aIf2Ancestor, nsnull);
|
||||
}
|
||||
|
||||
int last1 = content1Ancestors.Count() - 1;
|
||||
int last2 = content2Ancestors.Count() - 1;
|
||||
nsIContent* content1Ancestor = nsnull;
|
||||
nsIContent* content2Ancestor = nsnull;
|
||||
while (last1 >= 0 && last2 >= 0
|
||||
&& ((content1Ancestor = NS_STATIC_CAST(nsIContent*, content1Ancestors.ElementAt(last1)))
|
||||
== (content2Ancestor = NS_STATIC_CAST(nsIContent*, content2Ancestors.ElementAt(last2))))) {
|
||||
last1--;
|
||||
last2--;
|
||||
}
|
||||
|
||||
if (last1 < 0) {
|
||||
if (last2 < 0) {
|
||||
NS_ASSERTION(aContent1 == aContent2, "internal error?");
|
||||
return 0;
|
||||
} else {
|
||||
// aContent1 is an ancestor of aContent2
|
||||
return aIf1Ancestor;
|
||||
}
|
||||
} else {
|
||||
if (last2 < 0) {
|
||||
// aContent2 is an ancestor of aContent1
|
||||
return aIf2Ancestor;
|
||||
} else {
|
||||
// content1Ancestor != content2Ancestor, so they must be siblings with the same parent
|
||||
nsIContent* parent = content1Ancestor->GetParent();
|
||||
NS_ASSERTION(parent, "no common ancestor at all???");
|
||||
if (!parent) { // different documents??
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRInt32 index1 = parent->IndexOf(content1Ancestor);
|
||||
PRInt32 index2 = parent->IndexOf(content2Ancestor);
|
||||
if (index1 < 0 || index2 < 0) {
|
||||
// one of them must be anonymous; we can't determine the order
|
||||
return 0;
|
||||
}
|
||||
|
||||
return index1 - index2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
nsIFrame* nsLayoutUtils::GetLastSibling(nsIFrame* aFrame) {
|
||||
if (!aFrame) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIFrame* next;
|
||||
while ((next = aFrame->GetNextSibling()) != nsnull) {
|
||||
aFrame = next;
|
||||
}
|
||||
return aFrame;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIView*
|
||||
nsLayoutUtils::FindSiblingViewFor(nsIView* aParentView, nsIFrame* aFrame) {
|
||||
nsIFrame* parentViewFrame = NS_STATIC_CAST(nsIFrame*, aParentView->GetClientData());
|
||||
nsIContent* parentViewContent = parentViewFrame ? parentViewFrame->GetContent() : nsnull;
|
||||
for (nsIView* insertBefore = aParentView->GetFirstChild(); insertBefore;
|
||||
insertBefore = insertBefore->GetNextSibling()) {
|
||||
nsIFrame* f = NS_STATIC_CAST(nsIFrame*, insertBefore->GetClientData());
|
||||
if (!f) {
|
||||
// this view could be some anonymous view attached to a meaningful parent
|
||||
for (nsIView* searchView = insertBefore->GetParent(); searchView;
|
||||
searchView = searchView->GetParent()) {
|
||||
f = NS_STATIC_CAST(nsIFrame*, searchView->GetClientData());
|
||||
if (f) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(f, "Can't find a frame anywhere!");
|
||||
}
|
||||
if (f && CompareTreePosition(aFrame->GetContent(),
|
||||
f->GetContent(), parentViewContent) > 0) {
|
||||
// aFrame's content is after f's content, so put our view before f's view
|
||||
return insertBefore;
|
||||
}
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
//static
|
||||
nsIScrollableFrame*
|
||||
nsLayoutUtils::GetScrollableFrameFor(nsIFrame *aScrolledFrame)
|
||||
{
|
||||
nsIFrame *frame = aScrolledFrame->GetParent();
|
||||
if (!frame) {
|
||||
return nsnull;
|
||||
}
|
||||
frame = frame->GetParent();
|
||||
if (!frame) {
|
||||
return nsnull;
|
||||
}
|
||||
nsIScrollableFrame *sf;
|
||||
CallQueryInterface(frame, &sf);
|
||||
return sf;
|
||||
}
|
||||
|
||||
//static
|
||||
nsIScrollableFrame*
|
||||
nsLayoutUtils::GetScrollableFrameFor(nsIScrollableView *aScrollableView)
|
||||
{
|
||||
nsIFrame *frame = GetFrameFor(aScrollableView->View());
|
||||
if (frame && ((frame = frame->GetParent()))) {
|
||||
nsIScrollableFrame *sf;
|
||||
CallQueryInterface(frame, &sf);
|
||||
return sf;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
//static
|
||||
nsPresContext::ScrollbarStyles
|
||||
nsLayoutUtils::ScrollbarStylesOfView(nsIScrollableView *aScrollableView)
|
||||
{
|
||||
nsIScrollableFrame *sf = GetScrollableFrameFor(aScrollableView);
|
||||
return sf ? sf->GetScrollbarStyles() :
|
||||
nsPresContext::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN,
|
||||
NS_STYLE_OVERFLOW_HIDDEN);
|
||||
}
|
||||
|
||||
// static
|
||||
nsIScrollableView*
|
||||
nsLayoutUtils::GetNearestScrollingView(nsIView* aView, Direction aDirection)
|
||||
{
|
||||
// If aDirection is eEither, find first view with a scrolllable frame.
|
||||
// Otherwise, find the first view that has a scrollable frame whose
|
||||
// ScrollbarStyles is not NS_STYLE_OVERFLOW_HIDDEN in aDirection
|
||||
// and where there is something currently not visible
|
||||
// that can be scrolled to in aDirection.
|
||||
NS_ASSERTION(aView, "GetNearestScrollingView expects a non-null view");
|
||||
nsIScrollableView* scrollableView = nsnull;
|
||||
for (; aView; aView = aView->GetParent()) {
|
||||
scrollableView = aView->ToScrollableView();
|
||||
if (scrollableView) {
|
||||
nsPresContext::ScrollbarStyles ss =
|
||||
nsLayoutUtils::ScrollbarStylesOfView(scrollableView);
|
||||
nsIScrollableFrame *scrollableFrame = GetScrollableFrameFor(scrollableView);
|
||||
// NS_ASSERTION(scrollableFrame, "Must have scrollable frame for view!");
|
||||
if (!scrollableFrame) {
|
||||
// XXX Once bug 260652 is fixed we should get scrollable frames for HTML
|
||||
// frames and can uncomment the above scrollableFrame assertion instead
|
||||
// of using this if condition.
|
||||
break; // If scrollableView but not scrollable Frame, on an HTML <frame>
|
||||
}
|
||||
nsMargin margin = scrollableFrame->GetActualScrollbarSizes();
|
||||
// Get size of total scrollable area
|
||||
nscoord totalWidth, totalHeight;
|
||||
scrollableView->GetContainerSize(&totalWidth, &totalHeight);
|
||||
// Get size of currently visible area
|
||||
nsSize visibleSize = GetFrameFor(aView)->GetSize();
|
||||
// aDirection can be eHorizontal, eVertical, or eEither
|
||||
// If scrolling in a specific direction, require visible scrollbars or
|
||||
// something to scroll to in that direction.
|
||||
if (aDirection != eHorizontal &&
|
||||
ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN &&
|
||||
(aDirection == eEither || totalHeight > visibleSize.height || margin.right))
|
||||
break;
|
||||
if (aDirection != eVertical &&
|
||||
ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN &&
|
||||
(aDirection == eEither || totalWidth > visibleSize.width || margin.bottom))
|
||||
break;
|
||||
}
|
||||
}
|
||||
return scrollableView;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,505 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:cindent:ts=2:et:sw=2:
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#ifndef nsSpaceManager_h___
|
||||
#define nsSpaceManager_h___
|
||||
|
||||
#include "prclist.h"
|
||||
#include "nsIntervalSet.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
class nsIPresShell;
|
||||
class nsIFrame;
|
||||
class nsVoidArray;
|
||||
struct nsSize;
|
||||
struct nsHTMLReflowState;
|
||||
class nsPresContext;
|
||||
|
||||
#define NS_SPACE_MANAGER_CACHE_SIZE 4
|
||||
|
||||
/**
|
||||
* Information about a particular trapezoid within a band. The space described
|
||||
* by the trapezoid is in one of three states:
|
||||
* <ul>
|
||||
* <li>available
|
||||
* <li>occupied by one frame
|
||||
* <li>occupied by more than one frame
|
||||
* </ul>
|
||||
*/
|
||||
struct nsBandTrapezoid {
|
||||
enum State {Available, Occupied, OccupiedMultiple};
|
||||
|
||||
nscoord mTopY, mBottomY; // top and bottom y-coordinates
|
||||
nscoord mTopLeftX, mBottomLeftX; // left edge x-coordinates
|
||||
nscoord mTopRightX, mBottomRightX; // right edge x-coordinates
|
||||
State mState; // state of the space
|
||||
union {
|
||||
nsIFrame* mFrame; // single frame occupying the space
|
||||
const nsVoidArray* mFrames; // list of frames occupying the space
|
||||
};
|
||||
|
||||
// Get the height of the trapezoid
|
||||
nscoord GetHeight() const {return mBottomY - mTopY;}
|
||||
|
||||
// Get the bounding rect of the trapezoid
|
||||
inline void GetRect(nsRect& aRect) const;
|
||||
|
||||
// Set the trapezoid from a rectangle
|
||||
inline void operator=(const nsRect& aRect);
|
||||
|
||||
// Do these trapezoids have the same geometry, frame, and state?
|
||||
inline PRBool Equals(const nsBandTrapezoid& aTrap) const;
|
||||
|
||||
// Do these trapezoids have the same geometry?
|
||||
inline PRBool EqualGeometry(const nsBandTrapezoid& aTrap) const;
|
||||
|
||||
nsBandTrapezoid()
|
||||
: mTopY(0),
|
||||
mBottomY(0),
|
||||
mTopLeftX(0),
|
||||
mBottomLeftX(0),
|
||||
mTopRightX(0),
|
||||
mBottomRightX(0),
|
||||
mFrame(nsnull)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline void nsBandTrapezoid::GetRect(nsRect& aRect) const
|
||||
{
|
||||
aRect.x = PR_MIN(mTopLeftX, mBottomLeftX);
|
||||
aRect.y = mTopY;
|
||||
aRect.width = PR_MAX(mTopRightX, mBottomRightX);
|
||||
if (NS_MAXSIZE != aRect.width) {
|
||||
aRect.width -= aRect.x;
|
||||
}
|
||||
aRect.height = (NS_MAXSIZE == mBottomY) ? NS_MAXSIZE : mBottomY - mTopY;
|
||||
}
|
||||
|
||||
inline void nsBandTrapezoid::operator=(const nsRect& aRect)
|
||||
{
|
||||
mTopLeftX = mBottomLeftX = aRect.x;
|
||||
mTopRightX = mBottomRightX = aRect.XMost();
|
||||
mTopY = aRect.y;
|
||||
mBottomY = aRect.YMost();
|
||||
}
|
||||
|
||||
inline PRBool nsBandTrapezoid::Equals(const nsBandTrapezoid& aTrap) const
|
||||
{
|
||||
return (
|
||||
mTopLeftX == aTrap.mTopLeftX &&
|
||||
mBottomLeftX == aTrap.mBottomLeftX &&
|
||||
mTopRightX == aTrap.mTopRightX &&
|
||||
mBottomRightX == aTrap.mBottomRightX &&
|
||||
mTopY == aTrap.mTopY &&
|
||||
mBottomY == aTrap.mBottomY &&
|
||||
mState == aTrap.mState &&
|
||||
mFrame == aTrap.mFrame
|
||||
);
|
||||
}
|
||||
|
||||
inline PRBool nsBandTrapezoid::EqualGeometry(const nsBandTrapezoid& aTrap) const
|
||||
{
|
||||
return (
|
||||
mTopLeftX == aTrap.mTopLeftX &&
|
||||
mBottomLeftX == aTrap.mBottomLeftX &&
|
||||
mTopRightX == aTrap.mTopRightX &&
|
||||
mBottomRightX == aTrap.mBottomRightX &&
|
||||
mTopY == aTrap.mTopY &&
|
||||
mBottomY == aTrap.mBottomY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Structure used for describing the space within a band.
|
||||
* @see #GetBandData()
|
||||
*/
|
||||
struct nsBandData {
|
||||
PRInt32 mCount; // [out] actual number of trapezoids in the band data
|
||||
PRInt32 mSize; // [in] the size of the array (number of trapezoids)
|
||||
nsBandTrapezoid* mTrapezoids; // [out] array of length 'size'
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for dealing with bands of available space. The space manager
|
||||
* defines a coordinate space with an origin at (0, 0) that grows down
|
||||
* and to the right.
|
||||
*/
|
||||
class nsSpaceManager {
|
||||
public:
|
||||
nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
|
||||
~nsSpaceManager();
|
||||
|
||||
void* operator new(size_t aSize) CPP_THROW_NEW;
|
||||
void operator delete(void* aPtr, size_t aSize);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
/*
|
||||
* Get the frame that's associated with the space manager. This frame
|
||||
* created the space manager, and the world coordinate space is
|
||||
* relative to this frame.
|
||||
*
|
||||
* You can use QueryInterface() on this frame to get any additional
|
||||
* interfaces.
|
||||
*/
|
||||
nsIFrame* GetFrame() const { return mFrame; }
|
||||
|
||||
/**
|
||||
* Translate the current origin by the specified (dx, dy). This
|
||||
* creates a new local coordinate space relative to the current
|
||||
* coordinate space.
|
||||
*/
|
||||
void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
|
||||
|
||||
/**
|
||||
* Returns the current translation from local coordinate space to
|
||||
* world coordinate space. This represents the accumulated calls to
|
||||
* Translate().
|
||||
*/
|
||||
void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }
|
||||
|
||||
/**
|
||||
* Returns the x-most rect in the space manager, or 0 if there are no
|
||||
* rects.
|
||||
*
|
||||
* @return PR_TRUE if there are bands and PR_FALSE if there are no bands
|
||||
*/
|
||||
PRBool XMost(nscoord& aXMost) const;
|
||||
|
||||
/**
|
||||
* Returns the y-most of the bottommost band or 0 if there are no bands.
|
||||
*
|
||||
* @return PR_TRUE if there are bands and PR_FALSE if there are no bands
|
||||
*/
|
||||
PRBool YMost(nscoord& aYMost) const;
|
||||
|
||||
/**
|
||||
* Returns a band starting at the specified y-offset. The band data
|
||||
* indicates which parts of the band are available, and which parts
|
||||
* are unavailable
|
||||
*
|
||||
* The band data that is returned is in the coordinate space of the
|
||||
* local coordinate system.
|
||||
*
|
||||
* The local coordinate space origin, the y-offset, and the max size
|
||||
* describe a rectangle that's used to clip the underlying band of
|
||||
* available space, i.e.
|
||||
* {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
|
||||
* coordinate space
|
||||
*
|
||||
* @param aYOffset the y-offset of where the band begins. The coordinate is
|
||||
* relative to the upper-left corner of the local coordinate space
|
||||
* @param aMaxSize the size to use to constrain the band data
|
||||
* @param aBandData [in,out] used to return the list of trapezoids that
|
||||
* describe the available space and the unavailable space
|
||||
* @return NS_OK if successful and NS_ERROR_FAILURE if the band data is not
|
||||
* not large enough. The 'count' member of the band data struct
|
||||
* indicates how large the array of trapezoids needs to be
|
||||
*/
|
||||
nsresult GetBandData(nscoord aYOffset,
|
||||
const nsSize& aMaxSize,
|
||||
nsBandData& aBandData) const;
|
||||
|
||||
/**
|
||||
* Add a rectangular region of unavailable space. The space is
|
||||
* relative to the local coordinate system.
|
||||
*
|
||||
* The region is tagged with a frame
|
||||
*
|
||||
* @param aFrame the frame used to identify the region. Must not be NULL
|
||||
* @param aUnavailableSpace the bounding rect of the unavailable space
|
||||
* @return NS_OK if successful
|
||||
* NS_ERROR_FAILURE if there is already a region tagged with aFrame
|
||||
*/
|
||||
nsresult AddRectRegion(nsIFrame* aFrame,
|
||||
const nsRect& aUnavailableSpace);
|
||||
|
||||
/**
|
||||
* Remove the regions associated with this floating frame and its
|
||||
* next-sibling list. Some of the frames may never have been added;
|
||||
* we just skip those. This is not fully general; it only works as
|
||||
* long as the N frames to be removed are the last N frames to have
|
||||
* been added; if there's a frame in the middle of them that should
|
||||
* not be removed, YOU LOSE.
|
||||
*
|
||||
* This can only be done at the end of the life of this space manager. The only
|
||||
* methods it is safe to call after this are XMost() and YMost().
|
||||
*/
|
||||
nsresult RemoveTrailingRegions(nsIFrame* aFrameList);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Remove the region associated with aFrane.
|
||||
*
|
||||
* doesn't work in the general case!
|
||||
*
|
||||
* Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
|
||||
* tagged with aFrame
|
||||
*/
|
||||
nsresult RemoveRegion(nsIFrame* aFrame);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Clears the list of regions representing the unavailable space.
|
||||
*/
|
||||
void ClearRegions();
|
||||
|
||||
/**
|
||||
* Methods for dealing with the propagation of float damage during
|
||||
* reflow.
|
||||
*/
|
||||
PRBool HasFloatDamage()
|
||||
{
|
||||
return !mFloatDamage.IsEmpty();
|
||||
}
|
||||
|
||||
void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
|
||||
{
|
||||
mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
|
||||
}
|
||||
|
||||
PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
|
||||
{
|
||||
return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes the current state of the space manager onto a state stack.
|
||||
*/
|
||||
void PushState();
|
||||
|
||||
/**
|
||||
* Restores the space manager to the state at the top of the state stack,
|
||||
* then pops this state off the stack.
|
||||
*/
|
||||
void PopState();
|
||||
|
||||
/**
|
||||
* Get the top of the last region placed into the space manager, to
|
||||
* enforce the rule that a float can't be above an earlier float.
|
||||
* Returns the minimum nscoord value if there are no regions.
|
||||
*/
|
||||
nscoord GetLowestRegionTop();
|
||||
|
||||
/**
|
||||
* Return the coordinate of the lowest float matching aBreakType in this
|
||||
* space manager. Returns aY if there are no matching floats.
|
||||
*/
|
||||
nscoord ClearFloats(nscoord aY, PRUint8 aBreakType);
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Dump the state of the spacemanager out to a file
|
||||
*/
|
||||
nsresult List(FILE* out);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Structure that maintains information about the region associated
|
||||
// with a particular frame
|
||||
struct FrameInfo {
|
||||
nsIFrame* const mFrame;
|
||||
nsRect mRect; // rectangular region
|
||||
FrameInfo* mNext;
|
||||
|
||||
FrameInfo(nsIFrame* aFrame, const nsRect& aRect);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
~FrameInfo();
|
||||
#endif
|
||||
};
|
||||
|
||||
// Structure that stores the current state of a frame manager for
|
||||
// Save/Restore purposes.
|
||||
struct SpaceManagerState {
|
||||
nscoord mX, mY;
|
||||
nsIFrame *mLastFrame;
|
||||
nscoord mLowestTop;
|
||||
SpaceManagerState *mNext;
|
||||
};
|
||||
|
||||
public:
|
||||
// Doubly linked list of band rects
|
||||
struct BandRect : PRCListStr {
|
||||
nscoord mLeft, mTop;
|
||||
nscoord mRight, mBottom;
|
||||
PRInt32 mNumFrames; // number of frames occupying this rect
|
||||
union {
|
||||
nsIFrame* mFrame; // single frame occupying the space
|
||||
nsVoidArray* mFrames; // list of frames occupying the space
|
||||
};
|
||||
|
||||
BandRect(nscoord aLeft, nscoord aTop,
|
||||
nscoord aRight, nscoord aBottom,
|
||||
nsIFrame*);
|
||||
BandRect(nscoord aLeft, nscoord aTop,
|
||||
nscoord aRight, nscoord aBottom,
|
||||
nsVoidArray*);
|
||||
~BandRect();
|
||||
|
||||
// List operations
|
||||
BandRect* Next() const {return (BandRect*)PR_NEXT_LINK(this);}
|
||||
BandRect* Prev() const {return (BandRect*)PR_PREV_LINK(this);}
|
||||
void InsertBefore(BandRect* aBandRect) {PR_INSERT_BEFORE(aBandRect, this);}
|
||||
void InsertAfter(BandRect* aBandRect) {PR_INSERT_AFTER(aBandRect, this);}
|
||||
void Remove() {PR_REMOVE_LINK(this);}
|
||||
|
||||
// Split the band rect into two vertically, with this band rect becoming
|
||||
// the top part, and a new band rect being allocated and returned for the
|
||||
// bottom part
|
||||
//
|
||||
// Does not insert the new band rect into the linked list
|
||||
BandRect* SplitVertically(nscoord aBottom);
|
||||
|
||||
// Split the band rect into two horizontally, with this band rect becoming
|
||||
// the left part, and a new band rect being allocated and returned for the
|
||||
// right part
|
||||
//
|
||||
// Does not insert the new band rect into the linked list
|
||||
BandRect* SplitHorizontally(nscoord aRight);
|
||||
|
||||
// Accessor functions
|
||||
PRBool IsOccupiedBy(const nsIFrame*) const;
|
||||
void AddFrame(const nsIFrame*);
|
||||
void RemoveFrame(const nsIFrame*);
|
||||
PRBool HasSameFrameList(const BandRect* aBandRect) const;
|
||||
PRInt32 Length() const;
|
||||
};
|
||||
|
||||
// Circular linked list of band rects
|
||||
struct BandList : BandRect {
|
||||
BandList();
|
||||
|
||||
// Accessors
|
||||
PRBool IsEmpty() const {return PR_CLIST_IS_EMPTY((PRCListStr*)this);}
|
||||
BandRect* Head() const {return (BandRect*)PR_LIST_HEAD(this);}
|
||||
BandRect* Tail() const {return (BandRect*)PR_LIST_TAIL(this);}
|
||||
|
||||
// Operations
|
||||
void Append(BandRect* aBandRect) {PR_APPEND_LINK(aBandRect, this);}
|
||||
|
||||
// Remove and delete all the band rects in the list
|
||||
void Clear();
|
||||
};
|
||||
|
||||
protected:
|
||||
nsIFrame* const mFrame; // frame associated with the space manager
|
||||
nscoord mX, mY; // translation from local to global coordinate space
|
||||
BandList mBandList; // header/sentinel for circular linked list of band rects
|
||||
nscoord mLowestTop; // the lowest *top*
|
||||
FrameInfo* mFrameInfoMap;
|
||||
nsIntervalSet mFloatDamage;
|
||||
|
||||
SpaceManagerState *mSavedStates;
|
||||
SpaceManagerState mAutoState;
|
||||
|
||||
protected:
|
||||
FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
|
||||
FrameInfo* CreateFrameInfo(nsIFrame* aFrame, const nsRect& aRect);
|
||||
void DestroyFrameInfo(FrameInfo*);
|
||||
|
||||
void ClearFrameInfo();
|
||||
void ClearBandRects();
|
||||
|
||||
BandRect* GetNextBand(const BandRect* aBandRect) const;
|
||||
void DivideBand(BandRect* aBand, nscoord aBottom);
|
||||
PRBool CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
|
||||
PRBool JoinBands(BandRect* aBand, BandRect* aPrevBand);
|
||||
void AddRectToBand(BandRect* aBand, BandRect* aBandRect);
|
||||
void InsertBandRect(BandRect* aBandRect);
|
||||
|
||||
nsresult GetBandAvailableSpace(const BandRect* aBand,
|
||||
nscoord aY,
|
||||
const nsSize& aMaxSize,
|
||||
nsBandData& aAvailableSpace) const;
|
||||
|
||||
private:
|
||||
static PRInt32 sCachedSpaceManagerCount;
|
||||
static void* sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];
|
||||
|
||||
nsSpaceManager(const nsSpaceManager&); // no implementation
|
||||
void operator=(const nsSpaceManager&); // no implementation
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper class to manage maintenance of the space manager during
|
||||
* nsBlockFrame::Reflow. It automatically restores the old space
|
||||
* manager in the reflow state when the object goes out of scope.
|
||||
*/
|
||||
class nsAutoSpaceManager {
|
||||
public:
|
||||
nsAutoSpaceManager(nsHTMLReflowState& aReflowState)
|
||||
: mReflowState(aReflowState),
|
||||
#ifdef DEBUG
|
||||
mOwns(PR_TRUE),
|
||||
#endif
|
||||
mNew(nsnull),
|
||||
mOld(nsnull) {}
|
||||
|
||||
~nsAutoSpaceManager();
|
||||
|
||||
/**
|
||||
* Create a new space manager for the specified frame. This will
|
||||
* `remember' the old space manager, and install the new space
|
||||
* manager in the reflow state.
|
||||
*/
|
||||
nsresult
|
||||
CreateSpaceManagerFor(nsPresContext *aPresContext,
|
||||
nsIFrame *aFrame);
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* `Orphan' any space manager that the nsAutoSpaceManager created;
|
||||
* i.e., make it so that we don't destroy the space manager when we
|
||||
* go out of scope.
|
||||
*/
|
||||
void DebugOrphanSpaceManager() { mOwns = PR_FALSE; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
nsHTMLReflowState &mReflowState;
|
||||
#ifdef DEBUG
|
||||
PRBool mOwns;
|
||||
#endif
|
||||
nsSpaceManager *mNew;
|
||||
nsSpaceManager *mOld;
|
||||
};
|
||||
|
||||
#endif /* nsSpaceManager_h___ */
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -69,6 +69,11 @@ class nsIntervalSet;
|
|||
#define NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS 0x04000000
|
||||
#define NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS 0x08000000
|
||||
|
||||
// Set on any block that has descendant frames in the normal
|
||||
// flow with 'clear' set to something other than 'none'
|
||||
// (including <BR CLEAR="..."> frames)
|
||||
#define NS_BLOCK_HAS_CLEAR_CHILDREN 0x10000000
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
|
@ -224,6 +229,11 @@ public:
|
|||
virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
|
||||
nsIFrame* aNextInFlow);
|
||||
|
||||
// Determines whether the collapsed margin carried out of the last
|
||||
// line includes the margin-top of a line with clearance (in which
|
||||
// case we must avoid collapsing that margin with our bottom margin)
|
||||
PRBool CheckForCollapsedBottomMarginFromClearanceLine();
|
||||
|
||||
/** return the topmost block child based on y-index.
|
||||
* almost always the first or second line, if there is one.
|
||||
* accounts for lines that hold only compressed white space, etc.
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "nsIDOMHTMLBodyElement.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_MAX_ELEMENT_SIZE
|
||||
|
@ -79,13 +80,12 @@ nsBlockReflowContext::nsBlockReflowContext(nsPresContext* aPresContext,
|
|||
mMetrics.mFlags |= NS_REFLOW_CALC_MAX_WIDTH;
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockReflowContext::ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
nsHTMLReflowState& aRS,
|
||||
/* inout */ nsCollapsingMargin& aMargin)
|
||||
PRBool
|
||||
nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
|
||||
nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame, PRBool* aMayNeedRetry)
|
||||
{
|
||||
// Get aFrame's top margin
|
||||
aMargin.Include(aRS.mComputedMargin.top);
|
||||
// Include frame's top margin
|
||||
aMargin->Include(aRS.mComputedMargin.top);
|
||||
|
||||
// The inclusion of the bottom margin when empty is done by the caller
|
||||
// since it doesn't need to be done by the top-level (non-recursive)
|
||||
|
@ -93,48 +93,77 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
|||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, aRS.frame);
|
||||
printf(": %d => %d\n", aRS.mComputedMargin.top, aMargin.get());
|
||||
printf(": %d => %d\n", aRS.mComputedMargin.top, aMargin->get());
|
||||
#endif
|
||||
|
||||
// Calculate aFrame's generational top-margin from its child
|
||||
// blocks. Note that if aFrame has a non-zero top-border or
|
||||
PRBool dirtiedLine = PR_FALSE;
|
||||
|
||||
// Calculate the frame's generational top-margin from its child
|
||||
// blocks. Note that if the frame has a non-zero top-border or
|
||||
// top-padding then this step is skipped because it will be a margin
|
||||
// root. It is also skipped if the frame is a margin root for other
|
||||
// reasons.
|
||||
void* bf;
|
||||
if (0 == aRS.mComputedBorderPadding.top &&
|
||||
!(aRS.frame->GetStateBits() & NS_BLOCK_MARGIN_ROOT)) {
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID,
|
||||
NS_REINTERPRET_CAST(void**, &bf)))) {
|
||||
for (nsBlockFrame::line_iterator line = bf->begin_lines(),
|
||||
line_end = bf->end_lines();
|
||||
line != line_end; ++line) {
|
||||
PRBool isEmpty = line->IsEmpty();
|
||||
if (line->IsBlock()) {
|
||||
// Here is where we recur. Now that we have determined that a
|
||||
// generational collapse is required we need to compute the
|
||||
// child blocks margin and so in so that we can look into
|
||||
// it. For its margins to be computed we need to have a reflow
|
||||
// state for it. Since the reflow reason is irrelevant, we'll
|
||||
// arbitrarily make it a `resize' to avoid the path-plucking
|
||||
// behavior if we're in an incremental reflow.
|
||||
nsSize availSpace(aRS.mComputedWidth, aRS.mComputedHeight);
|
||||
nsHTMLReflowState reflowState(aPresContext, aRS, line->mFirstChild,
|
||||
availSpace, eReflowReason_Resize);
|
||||
ComputeCollapsedTopMargin(aPresContext, reflowState, aMargin);
|
||||
if (isEmpty)
|
||||
aMargin.Include(reflowState.mComputedMargin.bottom);
|
||||
}
|
||||
if (!isEmpty)
|
||||
break;
|
||||
!(aRS.frame->GetStateBits() & NS_BLOCK_MARGIN_ROOT) &&
|
||||
NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, &bf))) {
|
||||
nsBlockFrame* block = NS_STATIC_CAST(nsBlockFrame*, aRS.frame);
|
||||
|
||||
for (nsBlockFrame::line_iterator line = block->begin_lines(),
|
||||
line_end = block->end_lines();
|
||||
line != line_end; ++line) {
|
||||
if (!aClearanceFrame && line->HasClearance()) {
|
||||
// If we don't have a clearance frame, then we're computing
|
||||
// the collapsed margin in the first pass, assuming that all
|
||||
// lines have no clearance. So clear their clearance flags.
|
||||
line->ClearHasClearance();
|
||||
line->MarkDirty();
|
||||
dirtiedLine = PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool isEmpty = line->IsEmpty();
|
||||
if (line->IsBlock()) {
|
||||
nsBlockFrame* kidBlock = NS_STATIC_CAST(nsBlockFrame*, line->mFirstChild);
|
||||
if (kidBlock == aClearanceFrame) {
|
||||
line->SetHasClearance();
|
||||
line->MarkDirty();
|
||||
dirtiedLine = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
// Here is where we recur. Now that we have determined that a
|
||||
// generational collapse is required we need to compute the
|
||||
// child blocks margin and so in so that we can look into
|
||||
// it. For its margins to be computed we need to have a reflow
|
||||
// state for it. Since the reflow reason is irrelevant, we'll
|
||||
// arbitrarily make it a `resize' to avoid the path-plucking
|
||||
// behavior if we're in an incremental reflow.
|
||||
nsSize availSpace(aRS.mComputedWidth, aRS.mComputedHeight);
|
||||
nsHTMLReflowState reflowState(kidBlock->GetPresContext(),
|
||||
aRS, kidBlock,
|
||||
availSpace, eReflowReason_Resize);
|
||||
// Record that we're being optimistic by assuming the kid
|
||||
// has no clearance
|
||||
if (kidBlock->GetStyleDisplay()->mBreakType != NS_STYLE_CLEAR_NONE) {
|
||||
*aMayNeedRetry = PR_TRUE;
|
||||
}
|
||||
if (ComputeCollapsedTopMargin(reflowState, aMargin, aClearanceFrame, aMayNeedRetry)) {
|
||||
line->MarkDirty();
|
||||
dirtiedLine = PR_TRUE;
|
||||
}
|
||||
if (isEmpty)
|
||||
aMargin->Include(reflowState.mComputedMargin.bottom);
|
||||
}
|
||||
if (!isEmpty)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, aRS.frame);
|
||||
printf(": => %d\n", aMargin.get());
|
||||
#endif
|
||||
|
||||
return dirtiedLine;
|
||||
}
|
||||
|
||||
struct nsBlockHorizontalAlign {
|
||||
|
@ -302,7 +331,8 @@ nsPointDtor(void *aFrame, nsIAtom *aPropertyName,
|
|||
nsresult
|
||||
nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
PRBool aApplyTopMargin,
|
||||
nsCollapsingMargin& aPrevBottomMargin,
|
||||
nsCollapsingMargin& aPrevMargin,
|
||||
nscoord aClearance,
|
||||
PRBool aIsAdjacentWithTop,
|
||||
nsMargin& aComputedOffsets,
|
||||
nsHTMLReflowState& aFrameRS,
|
||||
|
@ -354,32 +384,8 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
|||
aFrameRS.reason = eReflowReason_Dirty;
|
||||
}
|
||||
|
||||
/* We build a different reflow context based on the width attribute of the block,
|
||||
* if it's a float.
|
||||
* Auto-width floats need to have their containing-block size set explicitly,
|
||||
* factoring in other floats that impact it.
|
||||
* It's possible this should be quirks-only.
|
||||
* All other blocks proceed normally.
|
||||
*/
|
||||
// XXXldb We should really fix this in nsHTMLReflowState::InitConstraints instead.
|
||||
const nsStylePosition* position = mFrame->GetStylePosition();
|
||||
nsStyleUnit widthUnit = position->mWidth.GetUnit();
|
||||
const nsStyleDisplay* display = mFrame->GetStyleDisplay();
|
||||
|
||||
if ((eStyleUnit_Auto == widthUnit) &&
|
||||
((NS_STYLE_FLOAT_LEFT == display->mFloats) ||
|
||||
(NS_STYLE_FLOAT_RIGHT == display->mFloats))) {
|
||||
// Initialize the reflow state and constrain the containing block's
|
||||
// width and height to the available width and height.
|
||||
aFrameRS.Init(mPresContext, mSpace.width, mSpace.height);
|
||||
}
|
||||
else {
|
||||
// Initialize the reflow state and use the containing block's computed
|
||||
// width and height (or derive appropriate values for an
|
||||
// absolutely positioned frame).
|
||||
aFrameRS.Init(mPresContext);
|
||||
}
|
||||
|
||||
aComputedOffsets = aFrameRS.mComputedOffsets;
|
||||
if (NS_STYLE_POSITION_RELATIVE == display->mPosition) {
|
||||
nsPropertyTable *propTable = mPresContext->PropertyTable();
|
||||
|
@ -404,23 +410,20 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
|||
mComputedWidth = aFrameRS.mComputedWidth;
|
||||
|
||||
if (aApplyTopMargin) {
|
||||
// Compute the childs collapsed top margin (its margin collpased
|
||||
// with its first childs top-margin -- recursively).
|
||||
ComputeCollapsedTopMargin(mPresContext, aFrameRS, aPrevBottomMargin);
|
||||
mTopMargin = aPrevMargin;
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, mOuterReflowState.frame);
|
||||
printf(": reflowing ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(" margin => %d\n", aPrevBottomMargin.get());
|
||||
printf(" margin => %d, clearance => %d\n", mTopMargin.get(), aClearance);
|
||||
#endif
|
||||
|
||||
// Adjust the available height if its constrained so that the
|
||||
// child frame doesn't think it can reflow into its margin area.
|
||||
if (NS_UNCONSTRAINEDSIZE != aFrameRS.availableHeight) {
|
||||
aFrameRS.availableHeight -= aPrevBottomMargin.get();
|
||||
aFrameRS.availableHeight -= mTopMargin.get() + aClearance;
|
||||
}
|
||||
mTopMargin = aPrevBottomMargin;
|
||||
}
|
||||
|
||||
// Compute x/y coordinate where reflow will begin. Use the rules
|
||||
|
@ -431,7 +434,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
|||
mStyleMargin = aFrameRS.mStyleMargin;
|
||||
mStylePadding = aFrameRS.mStylePadding;
|
||||
nscoord x;
|
||||
nscoord y = mSpace.y + mTopMargin.get();
|
||||
nscoord y = mSpace.y + mTopMargin.get() + aClearance;
|
||||
|
||||
// If it's a right floated element, then calculate the x-offset
|
||||
// differently
|
||||
|
@ -647,6 +650,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
|||
PRBool
|
||||
nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool aForceFit,
|
||||
nsLineBox* aLine,
|
||||
const nsMargin& aComputedOffsets,
|
||||
nsCollapsingMargin& aBottomMarginResult,
|
||||
nsRect& aInFlowBounds,
|
||||
|
@ -660,15 +664,13 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
|||
PRBool fits = PR_TRUE;
|
||||
nscoord x = mX;
|
||||
nscoord y = mY;
|
||||
// When deciding whether it's empty we also need to take into
|
||||
// account the overflow area
|
||||
|
||||
// XXXldb What should really matter is whether there exist non-
|
||||
// empty frames in the block (with appropriate whitespace munging).
|
||||
// Consider the case where we clip off the overflow with
|
||||
// 'overflow: -moz-hidden-unscrollable' (which doesn't currently
|
||||
// affect mOverflowArea, but probably should.
|
||||
if ((0 == mMetrics.height) && (0 == mMetrics.mOverflowArea.height))
|
||||
// Check whether the block's bottom margin collapses with its top
|
||||
// margin. See CSS 2.1 section 8.3.1; those rules seem to match
|
||||
// nsBlockFrame::IsEmpty(). Any such block must have zero height so
|
||||
// check that first.
|
||||
if (0 == mMetrics.height && !aLine->HasClearance() &&
|
||||
aLine->CachedIsEmpty())
|
||||
{
|
||||
// Collapse the bottom margin with the top margin that was already
|
||||
// applied.
|
||||
|
|
|
@ -39,10 +39,12 @@
|
|||
#define nsBlockReflowContext_h___
|
||||
|
||||
#include "nsIFrame.h"
|
||||
#include "nsHTMLReflowState.h"
|
||||
#include "nsHTMLReflowMetrics.h"
|
||||
|
||||
class nsBlockFrame;
|
||||
class nsBlockReflowState;
|
||||
class nsHTMLReflowState;
|
||||
class nsLineBox;
|
||||
class nsIFrame;
|
||||
class nsPresContext;
|
||||
class nsLineLayout;
|
||||
|
@ -62,7 +64,8 @@ public:
|
|||
|
||||
nsresult ReflowBlock(const nsRect& aSpace,
|
||||
PRBool aApplyTopMargin,
|
||||
nsCollapsingMargin& aPrevBottomMargin,
|
||||
nsCollapsingMargin& aPrevMargin,
|
||||
nscoord aClearance,
|
||||
PRBool aIsAdjacentWithTop,
|
||||
nsMargin& aComputedOffsets,
|
||||
nsHTMLReflowState& aReflowState,
|
||||
|
@ -70,6 +73,7 @@ public:
|
|||
|
||||
PRBool PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool aForceFit,
|
||||
nsLineBox* aLine,
|
||||
const nsMargin& aComputedOffsets,
|
||||
nsCollapsingMargin& aBottomMarginResult /* out */,
|
||||
nsRect& aInFlowBounds,
|
||||
|
@ -101,9 +105,23 @@ public:
|
|||
return mMetrics.mMaximumWidth;
|
||||
}
|
||||
|
||||
static void ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
nsHTMLReflowState& aRS,
|
||||
/* inout */ nsCollapsingMargin& aMargin);
|
||||
/**
|
||||
* Computes the collapsed top margin for a block whose reflow state is in aRS.
|
||||
* The computed margin is added into aMargin.
|
||||
* If aClearanceFrame is null then this is the first optimistic pass which shall assume
|
||||
* that no frames have clearance, and we clear the HasClearance on all frames encountered.
|
||||
* If non-null, this is the second pass and
|
||||
* the caller has decided aClearanceFrame needs clearance (and we will
|
||||
* therefore stop collapsing there); also, this function is responsible for marking
|
||||
* it with SetHasClearance.
|
||||
* If in the optimistic pass any frame is encountered that might possibly need
|
||||
* clearance (i.e., if we really needed the optimism assumption) then we set aMayNeedRetry
|
||||
* to true.
|
||||
* We return PR_TRUE if we changed the clearance state of any line and marked it dirty.
|
||||
*/
|
||||
static PRBool ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
|
||||
nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame,
|
||||
PRBool* aMayNeedRetry);
|
||||
|
||||
protected:
|
||||
nsPresContext* mPresContext;
|
||||
|
|
|
@ -60,7 +60,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
nsPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
PRBool aBlockMarginRoot)
|
||||
PRBool aTopMarginRoot,
|
||||
PRBool aBottomMarginRoot)
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
|
@ -71,14 +72,10 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
{
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
if (aBlockMarginRoot) {
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.top) {
|
||||
if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) {
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
if (aBottomMarginRoot || 0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
||||
|
@ -338,68 +335,6 @@ nsBlockReflowState::GetAvailableSpace(nscoord aY)
|
|||
#endif
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockReflowState::ClearPastFloats(PRUint8 aBreakType)
|
||||
{
|
||||
nscoord saveY, deltaY;
|
||||
|
||||
PRBool applyTopMargin = PR_FALSE;
|
||||
switch (aBreakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
||||
// Apply the previous margin before clearing
|
||||
saveY = mY + mPrevBottomMargin.get();
|
||||
ClearFloats(saveY, aBreakType);
|
||||
#ifdef NOISY_FLOAT_CLEARING
|
||||
nsFrame::ListTag(stdout, mBlock);
|
||||
printf(": ClearPastFloats: mPrevBottomMargin=%d saveY=%d oldY=%d newY=%d deltaY=%d\n",
|
||||
mPrevBottomMargin.get(), saveY, saveY - mPrevBottomMargin.get(), mY,
|
||||
mY - saveY);
|
||||
#endif
|
||||
|
||||
// Determine how far we just moved. If we didn't move then there
|
||||
// was nothing to clear to don't mess with the normal margin
|
||||
// collapsing behavior. In either case we need to restore the Y
|
||||
// coordinate to what it was before the clear.
|
||||
deltaY = mY - saveY;
|
||||
if (0 != deltaY) {
|
||||
// Pretend that the distance we just moved is a previous
|
||||
// blocks bottom margin. Note that GetAvailableSpace has been
|
||||
// done so that the available space calculations will be done
|
||||
// after clearing the appropriate floats.
|
||||
//
|
||||
// What we are doing here is applying CSS2 section 9.5.2's
|
||||
// rules for clearing - "The top margin of the generated box
|
||||
// is increased enough that the top border edge is below the
|
||||
// bottom outer edge of the floating boxes..."
|
||||
//
|
||||
// What this will do is cause the top-margin of the block
|
||||
// frame we are about to reflow to be collapsed with that
|
||||
// distance.
|
||||
|
||||
// XXXldb This doesn't handle collapsing with negative margins
|
||||
// correctly, although it's arguable what "correct" is.
|
||||
|
||||
// XXX Are all the other margins included by this point?
|
||||
mPrevBottomMargin.Zero();
|
||||
mPrevBottomMargin.Include(deltaY);
|
||||
mY = saveY;
|
||||
|
||||
// Force margin to be applied in this circumstance
|
||||
applyTopMargin = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Put mY back to its original value since no clearing
|
||||
// happened. That way the previous blocks bottom margin will
|
||||
// be applied properly.
|
||||
mY = saveY - mPrevBottomMargin.get();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return applyTopMargin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reconstruct the vertical margin before the line |aLine| in order to
|
||||
* do an incremental reflow that begins with |aLine| without reflowing
|
||||
|
@ -851,12 +786,10 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
|||
// See if the float should clear any preceeding floats...
|
||||
if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
|
||||
// XXXldb Does this handle vertical margins correctly?
|
||||
ClearFloats(mY, floatDisplay->mBreakType);
|
||||
mY = ClearFloats(mY, floatDisplay->mBreakType);
|
||||
}
|
||||
else {
|
||||
// Get the band of available space
|
||||
GetAvailableSpace();
|
||||
}
|
||||
|
||||
NS_ASSERTION(floatFrame->GetParent() == mBlock,
|
||||
"Float frame has wrong parent");
|
||||
|
@ -1154,14 +1087,14 @@ nsBlockReflowState::PlaceBelowCurrentLineFloats(nsFloatCacheList& aList)
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nscoord
|
||||
nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisyReflow) {
|
||||
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
||||
printf("clear floats: in: mY=%d aY=%d(%d)\n",
|
||||
mY, aY, aY - BorderPadding().top);
|
||||
printf("clear floats: in: aY=%d(%d)\n",
|
||||
aY, aY - BorderPadding().top);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1173,14 +1106,15 @@ nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType)
|
|||
|
||||
const nsMargin& bp = BorderPadding();
|
||||
nscoord newY = mSpaceManager->ClearFloats(aY - bp.top, aBreakType);
|
||||
mY = newY + bp.top;
|
||||
GetAvailableSpace();
|
||||
newY += bp.top;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisyReflow) {
|
||||
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
||||
printf("clear floats: out: mY=%d(%d)\n", mY, mY - bp.top);
|
||||
printf("clear floats: out: y=%d(%d)\n", newY, newY - bp.top);
|
||||
}
|
||||
#endif
|
||||
|
||||
return newY;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
nsPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
PRBool aBlockMarginRoot);
|
||||
PRBool aTopMarginRoot, PRBool aBottomMarginRoot);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
|
@ -85,12 +85,9 @@ public:
|
|||
|
||||
PRBool PlaceBelowCurrentLineFloats(nsFloatCacheList& aFloats);
|
||||
|
||||
// called when clearing a line with a break type caused by a BR past
|
||||
// floats, and also used internally by ClearPastFloats
|
||||
void ClearFloats(nscoord aY, PRUint8 aBreakType);
|
||||
|
||||
// called when clearing a block past floats
|
||||
PRBool ClearPastFloats(PRUint8 aBreakType);
|
||||
// Returns the first coordinate >= aY that clears the
|
||||
// indicated floats.
|
||||
nscoord ClearFloats(nscoord aY, PRUint8 aBreakType);
|
||||
|
||||
PRBool IsAdjacentWithTop() const {
|
||||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
|
|
|
@ -111,6 +111,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mSpecialHeightReflow = PR_FALSE;
|
||||
mFlags.mIsTopOfPage = PR_FALSE;
|
||||
mFlags.mNextInFlowUntouched = PR_FALSE;
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = nsnull;
|
||||
mPercentHeightReflowInitiator = nsnull;
|
||||
Init(aPresContext);
|
||||
|
@ -143,6 +145,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mSpecialHeightReflow = PR_FALSE;
|
||||
mFlags.mIsTopOfPage = PR_FALSE;
|
||||
mFlags.mNextInFlowUntouched = PR_FALSE;
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = nsnull;
|
||||
mPercentHeightReflowInitiator = nsnull;
|
||||
Init(aPresContext);
|
||||
|
@ -193,6 +197,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
|
@ -240,6 +246,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
|
@ -287,6 +295,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
|
|
|
@ -237,6 +237,13 @@ struct nsHTMLReflowState {
|
|||
// a frame (e.g. nsTableFrame) which initiates a special reflow for percent height calculations
|
||||
nsIFrame* mPercentHeightReflowInitiator;
|
||||
|
||||
// CSS margin collapsing sometimes requires us to reflow
|
||||
// optimistically assuming that margins collapse to see if clearance
|
||||
// is required. When we discover that clearance is required, we
|
||||
// store the frame in which clearance was discovered to the location
|
||||
// requested here.
|
||||
nsIFrame** mDiscoveredClearance;
|
||||
|
||||
// This value keeps track of how deeply nested a given reflow state
|
||||
// is from the top of the frame tree.
|
||||
PRInt16 mReflowDepth;
|
||||
|
@ -249,6 +256,7 @@ struct nsHTMLReflowState {
|
|||
PRUint16 mIsTopOfPage:1; // is the current context at the top of a page?
|
||||
PRUint16 mBlinks:1; // Keep track of text-decoration: blink
|
||||
PRUint16 mVisualBidiFormControl:1; // Keep track of descendants of form controls on Visual Bidi pages
|
||||
PRUint16 mHasClearance:1; // Block has clearance
|
||||
} mFlags;
|
||||
|
||||
#ifdef IBMBIDI
|
||||
|
|
|
@ -181,13 +181,14 @@ BreakTypeToString(PRUint8 aBreakType)
|
|||
char*
|
||||
nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const
|
||||
{
|
||||
PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,%s[0x%x]",
|
||||
PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,before:%s,after:%s[0x%x]",
|
||||
IsBlock() ? "block" : "inline",
|
||||
IsDirty() ? "dirty" : "clean",
|
||||
IsPreviousMarginDirty() ? "prevmargindirty" : "prevmarginclean",
|
||||
IsImpactedByFloat() ? "impacted" : "not impacted",
|
||||
IsLineWrapped() ? "wrapped" : "not wrapped",
|
||||
BreakTypeToString(GetBreakType()),
|
||||
BreakTypeToString(GetBreakTypeBefore()),
|
||||
BreakTypeToString(GetBreakTypeAfter()),
|
||||
mAllFlags);
|
||||
return aBuf;
|
||||
}
|
||||
|
@ -604,7 +605,7 @@ nsLineIterator::GetLine(PRInt32 aLineNumber,
|
|||
flags |= NS_LINE_FLAG_IS_BLOCK;
|
||||
}
|
||||
else {
|
||||
if (line->HasBreak())
|
||||
if (line->HasBreakAfter())
|
||||
flags |= NS_LINE_FLAG_ENDS_IN_BREAK;
|
||||
}
|
||||
*aLineFlags = flags;
|
||||
|
|
|
@ -246,6 +246,17 @@ public:
|
|||
return mFlags.mPreviousMarginDirty;
|
||||
}
|
||||
|
||||
// mHasClearance bit
|
||||
void SetHasClearance() {
|
||||
mFlags.mHasClearance = 1;
|
||||
}
|
||||
void ClearHasClearance() {
|
||||
mFlags.mHasClearance = 0;
|
||||
}
|
||||
PRBool HasClearance() const {
|
||||
return mFlags.mHasClearance;
|
||||
}
|
||||
|
||||
// mImpactedByFloat bit
|
||||
void SetLineIsImpactedByFloat(PRBool aValue) {
|
||||
NS_ASSERTION((PR_FALSE==aValue || PR_TRUE==aValue), "somebody is playing fast and loose with bools and bits!");
|
||||
|
@ -300,20 +311,37 @@ public:
|
|||
}
|
||||
|
||||
// mBreakType value
|
||||
PRBool HasBreak() const {
|
||||
return NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
|
||||
// Break information is applied *before* the line if the line is a block,
|
||||
// or *after* the line if the line is an inline. Confusing, I know, but
|
||||
// using different names should help.
|
||||
PRBool HasBreakBefore() const {
|
||||
return IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
|
||||
}
|
||||
PRBool HasFloatBreak() const {
|
||||
return NS_STYLE_CLEAR_LEFT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_LEFT_AND_RIGHT == mFlags.mBreakType;
|
||||
}
|
||||
void SetBreakType(PRUint8 aBreakType) {
|
||||
NS_WARN_IF_FALSE(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
|
||||
void SetBreakTypeBefore(PRUint8 aBreakType) {
|
||||
NS_ASSERTION(IsBlock(), "Only blocks have break-before");
|
||||
NS_ASSERTION(aBreakType <= NS_STYLE_CLEAR_LEFT_AND_RIGHT,
|
||||
"Only float break types are allowed before a line");
|
||||
mFlags.mBreakType = aBreakType;
|
||||
}
|
||||
PRUint8 GetBreakType() const {
|
||||
return mFlags.mBreakType;
|
||||
PRUint8 GetBreakTypeBefore() const {
|
||||
return IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
|
||||
}
|
||||
|
||||
PRBool HasBreakAfter() const {
|
||||
return !IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
|
||||
}
|
||||
void SetBreakTypeAfter(PRUint8 aBreakType) {
|
||||
NS_ASSERTION(!IsBlock(), "Only inlines have break-after");
|
||||
NS_ASSERTION(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
|
||||
mFlags.mBreakType = aBreakType;
|
||||
}
|
||||
PRBool HasFloatBreakAfter() const {
|
||||
return !IsBlock() && (NS_STYLE_CLEAR_LEFT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_LEFT_AND_RIGHT == mFlags.mBreakType);
|
||||
}
|
||||
PRUint8 GetBreakTypeAfter() const {
|
||||
return !IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
|
||||
}
|
||||
|
||||
// mCarriedOutBottomMargin value
|
||||
|
@ -427,6 +455,7 @@ public:
|
|||
struct FlagBits {
|
||||
PRUint32 mDirty : 1;
|
||||
PRUint32 mPreviousMarginDirty : 1;
|
||||
PRUint32 mHasClearance : 1;
|
||||
PRUint32 mBlock : 1;
|
||||
PRUint32 mImpactedByFloat : 1;
|
||||
PRUint32 mHasPercentageChild : 1;
|
||||
|
@ -436,7 +465,7 @@ public:
|
|||
PRUint32 mEmptyCacheState: 1;
|
||||
PRUint32 mBreakType : 4;
|
||||
|
||||
PRUint32 mChildCount : 19;
|
||||
PRUint32 mChildCount : 18;
|
||||
};
|
||||
|
||||
struct ExtraData {
|
||||
|
|
|
@ -1080,6 +1080,22 @@ nsSpaceManager::PopState()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSpaceManager::DiscardState()
|
||||
{
|
||||
NS_ASSERTION(mSavedStates, "Invalid call to DiscardState()!");
|
||||
|
||||
if (!mSavedStates) {
|
||||
return;
|
||||
}
|
||||
|
||||
SpaceManagerState *state = mSavedStates;
|
||||
mSavedStates = mSavedStates->mNext;
|
||||
if(state != &mAutoState) {
|
||||
delete state;
|
||||
}
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsSpaceManager::GetLowestRegionTop()
|
||||
{
|
||||
|
|
|
@ -311,6 +311,12 @@ public:
|
|||
*/
|
||||
void PopState();
|
||||
|
||||
/**
|
||||
* Pops the state off the stack without restoring it. Useful for speculative
|
||||
* reflow where we're not sure if we're going to keep the result.
|
||||
*/
|
||||
void DiscardState();
|
||||
|
||||
/**
|
||||
* Get the top of the last region placed into the space manager, to
|
||||
* enforce the rule that a float can't be above an earlier float.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,618 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:cindent:ts=2:et:sw=2:
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#ifndef nsBlockFrame_h___
|
||||
#define nsBlockFrame_h___
|
||||
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsHTMLParts.h"
|
||||
#include "nsAbsoluteContainingBlock.h"
|
||||
#include "nsLineBox.h"
|
||||
#include "nsReflowPath.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsStyleSet.h"
|
||||
|
||||
class nsBlockReflowState;
|
||||
class nsBulletFrame;
|
||||
class nsLineBox;
|
||||
class nsFirstLineFrame;
|
||||
class nsILineIterator;
|
||||
class nsIntervalSet;
|
||||
/**
|
||||
* Child list name indices
|
||||
* @see #GetAdditionalChildListName()
|
||||
*/
|
||||
#define NS_BLOCK_FRAME_FLOAT_LIST_INDEX 0
|
||||
#define NS_BLOCK_FRAME_BULLET_LIST_INDEX 1
|
||||
#define NS_BLOCK_FRAME_OVERFLOW_LIST_INDEX 2
|
||||
#define NS_BLOCK_FRAME_OVERFLOW_OOF_LIST_INDEX 3
|
||||
#define NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX 4
|
||||
#define NS_BLOCK_FRAME_LAST_LIST_INDEX NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX
|
||||
|
||||
// see nsHTMLParts.h for the public block state bits
|
||||
#define NS_BLOCK_HAS_LINE_CURSOR 0x01000000
|
||||
#define NS_BLOCK_HAS_OVERFLOW_LINES 0x02000000
|
||||
#define NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS 0x04000000
|
||||
#define NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS 0x08000000
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0xa6cf90df, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
extern const nsIID kBlockFrameCID;
|
||||
|
||||
/*
|
||||
* Base class for block and inline frames.
|
||||
* The block frame has an additional named child list:
|
||||
* - "Absolute-list" which contains the absolutely positioned frames
|
||||
*
|
||||
* @see nsLayoutAtoms::absoluteList
|
||||
*/
|
||||
class nsBlockFrame : public nsBlockFrameSuper
|
||||
{
|
||||
public:
|
||||
typedef nsLineList::iterator line_iterator;
|
||||
typedef nsLineList::const_iterator const_line_iterator;
|
||||
typedef nsLineList::reverse_iterator reverse_line_iterator;
|
||||
typedef nsLineList::const_reverse_iterator const_reverse_line_iterator;
|
||||
|
||||
line_iterator begin_lines() { return mLines.begin(); }
|
||||
line_iterator end_lines() { return mLines.end(); }
|
||||
const_line_iterator begin_lines() const { return mLines.begin(); }
|
||||
const_line_iterator end_lines() const { return mLines.end(); }
|
||||
reverse_line_iterator rbegin_lines() { return mLines.rbegin(); }
|
||||
reverse_line_iterator rend_lines() { return mLines.rend(); }
|
||||
const_reverse_line_iterator rbegin_lines() const { return mLines.rbegin(); }
|
||||
const_reverse_line_iterator rend_lines() const { return mLines.rend(); }
|
||||
|
||||
friend nsresult NS_NewBlockFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRUint32 aFlags);
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
|
||||
|
||||
// nsIFrame
|
||||
NS_IMETHOD Init(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
nsStyleContext* aContext,
|
||||
nsIFrame* aPrevInFlow);
|
||||
NS_IMETHOD SetInitialChildList(nsPresContext* aPresContext,
|
||||
nsIAtom* aListName,
|
||||
nsIFrame* aChildList);
|
||||
NS_IMETHOD AppendFrames(nsPresContext* aPresContext,
|
||||
nsIPresShell& aPresShell,
|
||||
nsIAtom* aListName,
|
||||
nsIFrame* aFrameList);
|
||||
NS_IMETHOD InsertFrames(nsPresContext* aPresContext,
|
||||
nsIPresShell& aPresShell,
|
||||
nsIAtom* aListName,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsIFrame* aFrameList);
|
||||
NS_IMETHOD RemoveFrame(nsPresContext* aPresContext,
|
||||
nsIPresShell& aPresShell,
|
||||
nsIAtom* aListName,
|
||||
nsIFrame* aOldFrame);
|
||||
virtual nsIFrame* GetFirstChild(nsIAtom* aListName) const;
|
||||
NS_IMETHOD SetParent(const nsIFrame* aParent);
|
||||
virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const;
|
||||
NS_IMETHOD Destroy(nsPresContext* aPresContext);
|
||||
NS_IMETHOD IsSplittable(nsSplittableType& aIsSplittable) const;
|
||||
virtual PRBool IsContainingBlock() const;
|
||||
NS_IMETHOD Paint(nsPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nsFramePaintLayer aWhichLayer,
|
||||
PRUint32 aFlags = 0);
|
||||
virtual nsIAtom* GetType() const;
|
||||
#ifdef DEBUG
|
||||
NS_IMETHOD List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const;
|
||||
NS_IMETHOD_(nsFrameState) GetDebugStateBits() const;
|
||||
NS_IMETHOD GetFrameName(nsAString& aResult) const;
|
||||
NS_IMETHOD VerifyTree() const;
|
||||
#endif
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
|
||||
#endif
|
||||
|
||||
// line cursor methods to speed up searching for the line(s)
|
||||
// containing a point. The basic idea is that we set the cursor
|
||||
// property if the lines' combinedArea.ys and combinedArea.yMosts
|
||||
// are non-decreasing (considering only non-empty combinedAreas;
|
||||
// empty combinedAreas never participate in event handling or
|
||||
// painting), and the block has sufficient number of lines. The
|
||||
// cursor property points to a "recently used" line. If we get a
|
||||
// series of GetFrameForPoint or Paint requests that work on lines
|
||||
// "near" the cursor, then we can find those nearby lines quickly by
|
||||
// starting our search at the cursor.
|
||||
|
||||
// Clear out line cursor because we're disturbing the lines (i.e., Reflow)
|
||||
void ClearLineCursor();
|
||||
// Get the first line that might contain y-coord 'y', or nsnull if you must search
|
||||
// all lines. If nonnull is returned then we guarantee that the lines'
|
||||
// combinedArea.ys and combinedArea.yMosts are non-decreasing.
|
||||
// The actual line returned might not contain 'y', but if not, it is guaranteed
|
||||
// to be before any line which does contain 'y'.
|
||||
nsLineBox* GetFirstLineContaining(nscoord y);
|
||||
// Set the line cursor to our first line. Only call this if you
|
||||
// guarantee that the lines' combinedArea.ys and combinedArea.yMosts
|
||||
// are non-decreasing.
|
||||
void SetupLineCursor();
|
||||
|
||||
nsresult GetFrameForPointUsing(nsPresContext* aPresContext,
|
||||
const nsPoint& aPoint,
|
||||
nsIAtom* aList,
|
||||
nsFramePaintLayer aWhichLayer,
|
||||
PRBool aConsiderSelf,
|
||||
nsIFrame** aFrame);
|
||||
NS_IMETHOD GetFrameForPoint(nsPresContext* aPresContext, const nsPoint& aPoint, nsFramePaintLayer aWhichLayer, nsIFrame** aFrame);
|
||||
NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus);
|
||||
NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild);
|
||||
|
||||
NS_IMETHOD IsVisibleForPainting(nsPresContext * aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
PRBool aCheckVis,
|
||||
PRBool* aIsVisible);
|
||||
|
||||
virtual PRBool IsEmpty();
|
||||
virtual PRBool IsSelfEmpty();
|
||||
|
||||
// nsIHTMLReflow
|
||||
NS_IMETHOD Reflow(nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
NS_IMETHOD AttributeChanged(nsPresContext* aPresContext,
|
||||
nsIContent* aChild,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType);
|
||||
|
||||
#ifdef DO_SELECTION
|
||||
NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus);
|
||||
|
||||
NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus);
|
||||
|
||||
nsIFrame * FindHitFrame(nsBlockFrame * aBlockFrame,
|
||||
const nscoord aX, const nscoord aY,
|
||||
const nsPoint & aPoint);
|
||||
|
||||
#endif
|
||||
|
||||
virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
|
||||
nsIFrame* aNextInFlow);
|
||||
|
||||
/** return the topmost block child based on y-index.
|
||||
* almost always the first or second line, if there is one.
|
||||
* accounts for lines that hold only compressed white space, etc.
|
||||
*/
|
||||
nsIFrame* GetTopBlockChild(nsPresContext *aPresContext);
|
||||
|
||||
// Returns the line containing aFrame, or end_lines() if the frame
|
||||
// isn't in the block.
|
||||
line_iterator FindLineFor(nsIFrame* aFrame);
|
||||
|
||||
static nsresult GetCurrentLine(nsBlockReflowState *aState, nsLineBox **aOutCurrentLine);
|
||||
|
||||
inline nscoord GetAscent() { return mAscent; }
|
||||
|
||||
// Create a contination for aPlaceholder and its out of flow frame and
|
||||
// add it to the list of overflow floats
|
||||
nsresult SplitPlaceholder(nsPresContext& aPresContext, nsIFrame& aPlaceholder);
|
||||
|
||||
void UndoSplitPlaceholders(nsBlockReflowState& aState,
|
||||
nsIFrame* aLastPlaceholder);
|
||||
|
||||
virtual void PaintChild(nsPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nsIFrame* aFrame,
|
||||
nsFramePaintLayer aWhichLayer,
|
||||
PRUint32 aFlags = 0) {
|
||||
nsContainerFrame::PaintChild(aPresContext, aRenderingContext,
|
||||
aDirtyRect, aFrame, aWhichLayer, aFlags);
|
||||
}
|
||||
|
||||
protected:
|
||||
nsBlockFrame();
|
||||
virtual ~nsBlockFrame();
|
||||
|
||||
already_AddRefed<nsStyleContext> GetFirstLetterStyle(nsPresContext* aPresContext)
|
||||
{
|
||||
return aPresContext->StyleSet()->
|
||||
ProbePseudoStyleFor(mContent,
|
||||
nsCSSPseudoElements::firstLetter, mStyleContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overides member function of nsHTMLContainerFrame. Needed to handle the
|
||||
* lines in a nsBlockFrame properly.
|
||||
*/
|
||||
virtual void PaintTextDecorationLines(nsIRenderingContext& aRenderingContext,
|
||||
nscolor aColor,
|
||||
nscoord aOffset,
|
||||
nscoord aAscent,
|
||||
nscoord aSize);
|
||||
|
||||
/**
|
||||
* GetClosestLine will return the line that VERTICALLY owns the point closest to aPoint.y
|
||||
* aOrigin is the offset for this block frame to its frame.
|
||||
* aPoint is the point to search for.
|
||||
* aClosestLine is the result.
|
||||
*/
|
||||
nsresult GetClosestLine(nsILineIterator *aLI,
|
||||
const nsPoint &aOrigin,
|
||||
const nsPoint &aPoint,
|
||||
PRInt32 &aClosestLine);
|
||||
|
||||
void TryAllLines(nsLineList::iterator* aIterator,
|
||||
nsLineList::iterator* aEndIterator,
|
||||
PRBool* aInOverflowLines);
|
||||
|
||||
void SetFlags(PRUint32 aFlags) {
|
||||
mState &= ~NS_BLOCK_FLAGS_MASK;
|
||||
mState |= aFlags;
|
||||
}
|
||||
|
||||
PRBool HaveOutsideBullet() const {
|
||||
#if defined(DEBUG) && !defined(DEBUG_rods)
|
||||
if(mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET) {
|
||||
NS_ASSERTION(mBullet,"NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET flag set and no mBullet");
|
||||
}
|
||||
#endif
|
||||
return 0 != (mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET);
|
||||
}
|
||||
|
||||
/** move the frames contained by aLine by aDY
|
||||
* if aLine is a block, it's child floats are added to the state manager
|
||||
*/
|
||||
void SlideLine(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine, nscoord aDY);
|
||||
|
||||
virtual PRIntn GetSkipSides() const;
|
||||
|
||||
virtual void ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
nsBlockReflowState& aState,
|
||||
nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
void ComputeCombinedArea(const nsHTMLReflowState& aReflowState,
|
||||
nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
/** add the frames in aFrameList to this block after aPrevSibling
|
||||
* this block thinks in terms of lines, but the frame construction code
|
||||
* knows nothing about lines at all. So we need to find the line that
|
||||
* contains aPrevSibling and add aFrameList after aPrevSibling on that line.
|
||||
* new lines are created as necessary to handle block data in aFrameList.
|
||||
*/
|
||||
nsresult AddFrames(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrameList,
|
||||
nsIFrame* aPrevSibling);
|
||||
|
||||
/** does all the real work for removing aDeletedFrame from this
|
||||
* finds the line containing aFrame.
|
||||
* handled continued frames
|
||||
* marks lines dirty as needed
|
||||
*/
|
||||
nsresult DoRemoveFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aDeletedFrame);
|
||||
|
||||
/** grab overflow lines from this block's prevInFlow, and make them
|
||||
* part of this block's mLines list.
|
||||
* @return PR_TRUE if any lines were drained.
|
||||
*/
|
||||
PRBool DrainOverflowLines();
|
||||
|
||||
/**
|
||||
* Remove a float from our float list and also the float cache
|
||||
* for the line its placeholder is on.
|
||||
*/
|
||||
line_iterator RemoveFloat(nsIFrame* aFloat);
|
||||
|
||||
// Remove a float, abs, rel positioned frame from the appropriate block's list
|
||||
static void DoRemoveOutOfFlowFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
/** set up the conditions necessary for an initial reflow */
|
||||
nsresult PrepareInitialReflow(nsBlockReflowState& aState);
|
||||
|
||||
/** set up the conditions necessary for an styleChanged reflow */
|
||||
nsresult PrepareStyleChangedReflow(nsBlockReflowState& aState);
|
||||
|
||||
/** set up the conditions necessary for an incremental reflow.
|
||||
* the primary task is to mark the minimumly sufficient lines dirty.
|
||||
*/
|
||||
nsresult PrepareChildIncrementalReflow(nsBlockReflowState& aState);
|
||||
|
||||
/**
|
||||
* Retarget an inline incremental reflow from continuing frames that
|
||||
* will be destroyed.
|
||||
*
|
||||
* @param aState |aState.mNextRCFrame| contains the next frame in
|
||||
* the reflow path; this will be ``rewound'' to either the target
|
||||
* frame's primary frame, or to the first continuation frame after a
|
||||
* ``hard break''. In other words, it will be set to the closest
|
||||
* continuation which will not be destroyed by the unconstrained
|
||||
* reflow. The remaining frames in the reflow path for
|
||||
* |aState.mReflowState.reflowCommand| will be altered similarly.
|
||||
*
|
||||
* @param aLine is initially the line box that contains the target
|
||||
* frame. It will be ``rewound'' in lockstep with
|
||||
* |aState.mNextRCFrame|.
|
||||
*
|
||||
* @param aPrevInFlow points to the target frame's prev-in-flow.
|
||||
*/
|
||||
void RetargetInlineIncrementalReflow(nsReflowPath::iterator &aFrame,
|
||||
line_iterator &aLine,
|
||||
nsIFrame *aPrevInFlow);
|
||||
|
||||
/** set up the conditions necessary for an resize reflow
|
||||
* the primary task is to mark the minimumly sufficient lines dirty.
|
||||
*/
|
||||
nsresult PrepareResizeReflow(nsBlockReflowState& aState);
|
||||
|
||||
/** reflow all lines that have been marked dirty */
|
||||
nsresult ReflowDirtyLines(nsBlockReflowState& aState);
|
||||
|
||||
//----------------------------------------
|
||||
// Methods for line reflow
|
||||
/**
|
||||
* Reflow a line.
|
||||
* @param aState the current reflow state
|
||||
* @param aLine the line to reflow. can contain a single block frame
|
||||
* or contain 1 or more inline frames.
|
||||
* @param aKeepReflowGoing [OUT] indicates whether the caller should continue to reflow more lines
|
||||
* @param aDamageDirtyArea if PR_TRUE, do extra work to mark the changed areas as damaged for painting
|
||||
* this indicates that frames may have changed size, for example
|
||||
*/
|
||||
nsresult ReflowLine(nsBlockReflowState& aState,
|
||||
line_iterator aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRBool aDamageDirtyArea = PR_FALSE);
|
||||
|
||||
// Return PR_TRUE if aLine gets pushed.
|
||||
PRBool PlaceLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
line_iterator aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRBool aUpdateMaximumWidth);
|
||||
|
||||
/**
|
||||
* Mark |aLine| dirty, and, if necessary because of possible
|
||||
* pull-up, mark the previous line dirty as well.
|
||||
*/
|
||||
nsresult MarkLineDirty(line_iterator aLine);
|
||||
|
||||
// XXX blech
|
||||
void PostPlaceLine(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
nscoord aMaxElementWidth);
|
||||
|
||||
// XXX where to go
|
||||
PRBool ShouldJustifyLine(nsBlockReflowState& aState,
|
||||
line_iterator aLine);
|
||||
|
||||
void DeleteLine(nsBlockReflowState& aState,
|
||||
nsLineList::iterator aLine,
|
||||
nsLineList::iterator aLineEnd);
|
||||
|
||||
//----------------------------------------
|
||||
// Methods for individual frame reflow
|
||||
|
||||
PRBool ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine);
|
||||
|
||||
nsresult ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
line_iterator aLine,
|
||||
PRBool* aKeepGoing);
|
||||
|
||||
nsresult ReflowInlineFrames(nsBlockReflowState& aState,
|
||||
line_iterator aLine,
|
||||
PRBool* aKeepLineGoing,
|
||||
PRBool aDamageDirtyArea,
|
||||
PRBool aUpdateMaximumWidth = PR_FALSE);
|
||||
|
||||
nsresult DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
line_iterator aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus,
|
||||
PRBool aUpdateMaximumWidth,
|
||||
PRBool aDamageDirtyArea);
|
||||
|
||||
nsresult ReflowInlineFrame(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
line_iterator aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRUint8* aLineReflowStatus);
|
||||
|
||||
// An incomplete aReflowStatus indicates the float should be split
|
||||
// but only if the available height is constrained.
|
||||
nsresult ReflowFloat(nsBlockReflowState& aState,
|
||||
nsPlaceholderFrame* aPlaceholder,
|
||||
nsFloatCache* aFloatCache,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
|
||||
//----------------------------------------
|
||||
// Methods for pushing/pulling lines/frames
|
||||
|
||||
virtual nsresult CreateContinuationFor(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRBool& aMadeNewFrame);
|
||||
|
||||
// Push aLine which contains a positioned element that was truncated. Clean up any
|
||||
// placeholders on the same line that were continued. Set aKeepReflowGoing to false.
|
||||
void PushTruncatedPlaceholderLine(nsBlockReflowState& aState,
|
||||
line_iterator aLine,
|
||||
nsIFrame* aLastPlaceholder,
|
||||
PRBool& aKeepReflowGoing);
|
||||
|
||||
nsresult SplitLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
line_iterator aLine,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
nsresult PullFrame(nsBlockReflowState& aState,
|
||||
line_iterator aLine,
|
||||
PRBool aDamageDeletedLine,
|
||||
nsIFrame*& aFrameResult);
|
||||
|
||||
nsresult PullFrameFrom(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
nsBlockFrame* aFromContainer,
|
||||
PRBool aFromOverflowLine,
|
||||
nsLineList::iterator aFromLine,
|
||||
PRBool aDamageDeletedLines,
|
||||
nsIFrame*& aFrameResult);
|
||||
|
||||
void PushLines(nsBlockReflowState& aState,
|
||||
nsLineList::iterator aLineBefore);
|
||||
|
||||
|
||||
void ReparentFloats(nsIFrame* aFirstFrame,
|
||||
nsBlockFrame* aOldParent, PRBool aFromOverflow);
|
||||
|
||||
//----------------------------------------
|
||||
//XXX
|
||||
virtual void PaintChildren(nsPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nsFramePaintLayer aWhichLayer,
|
||||
PRUint32 aFlags = 0);
|
||||
|
||||
void PaintFloats(nsPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
void PropagateFloatDamage(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
nscoord aDeltaY);
|
||||
|
||||
void BuildFloatList(nsBlockReflowState& aState);
|
||||
|
||||
//----------------------------------------
|
||||
// List handling kludge
|
||||
|
||||
void RenumberLists(nsPresContext* aPresContext);
|
||||
|
||||
PRBool RenumberListsInBlock(nsPresContext* aPresContext,
|
||||
nsBlockFrame* aContainerFrame,
|
||||
PRInt32* aOrdinal,
|
||||
PRInt32 aDepth);
|
||||
|
||||
PRBool RenumberListsFor(nsPresContext* aPresContext, nsIFrame* aKid, PRInt32* aOrdinal, PRInt32 aDepth);
|
||||
|
||||
PRBool FrameStartsCounterScope(nsIFrame* aFrame);
|
||||
|
||||
nsresult UpdateBulletPosition(nsBlockReflowState& aState);
|
||||
|
||||
void ReflowBullet(nsBlockReflowState& aState,
|
||||
nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
nsLineList* GetOverflowLines() const;
|
||||
nsLineList* RemoveOverflowLines();
|
||||
nsresult SetOverflowLines(nsLineList* aOverflowLines);
|
||||
|
||||
nsFrameList* GetOverflowPlaceholders() const;
|
||||
nsFrameList* RemoveOverflowPlaceholders();
|
||||
nsresult SetOverflowPlaceholders(nsFrameList* aOverflowPlaceholders);
|
||||
|
||||
nsFrameList* GetOverflowOutOfFlows() const;
|
||||
nsFrameList* RemoveOverflowOutOfFlows();
|
||||
nsresult SetOverflowOutOfFlows(nsFrameList* aFloaters);
|
||||
|
||||
nsIFrame* LastChild();
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PRBool IsChild(nsIFrame* aFrame);
|
||||
void VerifyLines(PRBool aFinalCheckOK);
|
||||
void VerifyOverflowSituation();
|
||||
PRInt32 GetDepth() const;
|
||||
#endif
|
||||
|
||||
// Ascent of our first line to support 'vertical-align: baseline' in table-cells
|
||||
nscoord mAscent;
|
||||
|
||||
nsLineList mLines;
|
||||
|
||||
// List of all floats in this block
|
||||
nsFrameList mFloats;
|
||||
|
||||
// XXX_fix_me: subclass one more time!
|
||||
// For list-item frames, this is the bullet frame.
|
||||
nsBulletFrame* mBullet;
|
||||
|
||||
friend class nsBlockReflowState;
|
||||
|
||||
private:
|
||||
nsAbsoluteContainingBlock mAbsoluteContainer;
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
public:
|
||||
static PRBool gLamePaintMetrics;
|
||||
static PRBool gLameReflowMetrics;
|
||||
static PRBool gNoisy;
|
||||
static PRBool gNoisyDamageRepair;
|
||||
static PRBool gNoisyMaxElementWidth;
|
||||
static PRBool gNoisyReflow;
|
||||
static PRBool gReallyNoisyReflow;
|
||||
static PRBool gNoisySpaceManager;
|
||||
static PRBool gVerifyLines;
|
||||
static PRBool gDisableResizeOpt;
|
||||
|
||||
static PRInt32 gNoiseIndent;
|
||||
|
||||
static const char* kReflowCommandType[];
|
||||
|
||||
protected:
|
||||
static void InitDebugFlags();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* nsBlockFrame_h___ */
|
||||
|
|
@ -1,794 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:cindent:ts=2:et:sw=2:
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Baron <dbaron@dbaron.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "nsBlockReflowContext.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsSpaceManager.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsFrameManager.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsHTMLReflowCommand.h"
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsLineBox.h"
|
||||
#include "nsIDOMHTMLTableCellElement.h"
|
||||
#include "nsIDOMHTMLBodyElement.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_MAX_ELEMENT_SIZE
|
||||
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#else
|
||||
#undef NOISY_MAX_ELEMENT_SIZE
|
||||
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#endif
|
||||
|
||||
nsBlockReflowContext::nsBlockReflowContext(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState& aParentRS,
|
||||
PRBool aComputeMaxElementWidth,
|
||||
PRBool aComputeMaximumWidth)
|
||||
: mPresContext(aPresContext),
|
||||
mOuterReflowState(aParentRS),
|
||||
mMetrics(aComputeMaxElementWidth),
|
||||
mComputeMaximumWidth(aComputeMaximumWidth)
|
||||
{
|
||||
mStyleBorder = nsnull;
|
||||
mStyleMargin = nsnull;
|
||||
mStylePadding = nsnull;
|
||||
if (mComputeMaximumWidth)
|
||||
mMetrics.mFlags |= NS_REFLOW_CALC_MAX_WIDTH;
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockReflowContext::ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
nsHTMLReflowState& aRS,
|
||||
/* inout */ nsCollapsingMargin& aMargin)
|
||||
{
|
||||
// Get aFrame's top margin
|
||||
aMargin.Include(aRS.mComputedMargin.top);
|
||||
|
||||
// The inclusion of the bottom margin when empty is done by the caller
|
||||
// since it doesn't need to be done by the top-level (non-recursive)
|
||||
// caller.
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, aRS.frame);
|
||||
printf(": %d => %d\n", aRS.mComputedMargin.top, aMargin.get());
|
||||
#endif
|
||||
|
||||
// Calculate aFrame's generational top-margin from its child
|
||||
// blocks. Note that if aFrame has a non-zero top-border or
|
||||
// top-padding then this step is skipped because it will be a margin
|
||||
// root. It is also skipped if the frame is a margin root for other
|
||||
// reasons.
|
||||
if (0 == aRS.mComputedBorderPadding.top &&
|
||||
!(aRS.frame->GetStateBits() & NS_BLOCK_MARGIN_ROOT)) {
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID,
|
||||
NS_REINTERPRET_CAST(void**, &bf)))) {
|
||||
for (nsBlockFrame::line_iterator line = bf->begin_lines(),
|
||||
line_end = bf->end_lines();
|
||||
line != line_end; ++line) {
|
||||
PRBool isEmpty = line->IsEmpty();
|
||||
if (line->IsBlock()) {
|
||||
// Here is where we recur. Now that we have determined that a
|
||||
// generational collapse is required we need to compute the
|
||||
// child blocks margin and so in so that we can look into
|
||||
// it. For its margins to be computed we need to have a reflow
|
||||
// state for it. Since the reflow reason is irrelevant, we'll
|
||||
// arbitrarily make it a `resize' to avoid the path-plucking
|
||||
// behavior if we're in an incremental reflow.
|
||||
nsSize availSpace(aRS.mComputedWidth, aRS.mComputedHeight);
|
||||
nsHTMLReflowState reflowState(aPresContext, aRS, line->mFirstChild,
|
||||
availSpace, eReflowReason_Resize);
|
||||
ComputeCollapsedTopMargin(aPresContext, reflowState, aMargin);
|
||||
if (isEmpty)
|
||||
aMargin.Include(reflowState.mComputedMargin.bottom);
|
||||
}
|
||||
if (!isEmpty)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, aRS.frame);
|
||||
printf(": => %d\n", aMargin.get());
|
||||
#endif
|
||||
}
|
||||
|
||||
struct nsBlockHorizontalAlign {
|
||||
nscoord mXOffset; // left edge
|
||||
nscoord mLeftMargin;
|
||||
nscoord mRightMargin;
|
||||
};
|
||||
|
||||
// Given the width of the block frame and a suggested x-offset calculate
|
||||
// the actual x-offset taking into account horizontal alignment. Also returns
|
||||
// the actual left and right margin
|
||||
void
|
||||
nsBlockReflowContext::AlignBlockHorizontally(nscoord aWidth,
|
||||
nsBlockHorizontalAlign &aAlign)
|
||||
{
|
||||
// Initialize OUT parameters
|
||||
aAlign.mLeftMargin = mMargin.left;
|
||||
aAlign.mRightMargin = mMargin.right;
|
||||
|
||||
// Get style unit associated with the left and right margins
|
||||
nsStyleUnit leftUnit = mStyleMargin->mMargin.GetLeftUnit();
|
||||
nsStyleUnit rightUnit = mStyleMargin->mMargin.GetRightUnit();
|
||||
|
||||
// Apply post-reflow horizontal alignment. When a block element
|
||||
// doesn't use it all of the available width then we need to
|
||||
// align it using the text-align property.
|
||||
if (NS_UNCONSTRAINEDSIZE != mSpace.width &&
|
||||
NS_UNCONSTRAINEDSIZE != mOuterReflowState.mComputedWidth) {
|
||||
// It is possible that the object reflowed was given a
|
||||
// constrained width and ended up picking a different width
|
||||
// (e.g. a table width a set width that ended up larger
|
||||
// because its contents required it). When this happens we
|
||||
// need to recompute auto margins because the reflow state's
|
||||
// computations are no longer valid.
|
||||
if (aWidth != mComputedWidth) {
|
||||
if (eStyleUnit_Auto == leftUnit) {
|
||||
aAlign.mXOffset = mSpace.x;
|
||||
aAlign.mLeftMargin = 0;
|
||||
}
|
||||
if (eStyleUnit_Auto == rightUnit) {
|
||||
aAlign.mRightMargin = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute how much remaining space there is, and in special
|
||||
// cases apply it (normally we should get zero here because of
|
||||
// the logic in nsHTMLReflowState).
|
||||
nscoord remainingSpace = mSpace.XMost() - (aAlign.mXOffset + aWidth +
|
||||
aAlign.mRightMargin);
|
||||
if (remainingSpace > 0) {
|
||||
// The block/table frame didn't use all of the available
|
||||
// space. Synthesize margins for its horizontal placement.
|
||||
if (eStyleUnit_Auto == leftUnit) {
|
||||
if (eStyleUnit_Auto == rightUnit) {
|
||||
// When both margins are auto, we center the block
|
||||
aAlign.mXOffset += remainingSpace / 2;
|
||||
}
|
||||
else {
|
||||
// When the left margin is auto we right align the block
|
||||
aAlign.mXOffset += remainingSpace;
|
||||
}
|
||||
}
|
||||
else if (eStyleUnit_Auto != rightUnit) {
|
||||
// The block/table doesn't have auto margins.
|
||||
|
||||
// For normal (non-table) blocks we don't get here because
|
||||
// nsHTMLReflowState::CalculateBlockSideMargins handles this.
|
||||
// (I think there may be an exception to that, though...)
|
||||
|
||||
// We use a special value of the text-align property for
|
||||
// HTML alignment (the CENTER element and DIV ALIGN=...)
|
||||
// since it acts on blocks and tables rather than just
|
||||
// being a text-align.
|
||||
// So, check the text-align value from the parent to see if
|
||||
// it has one of these special values.
|
||||
const nsStyleText* styleText = mOuterReflowState.mStyleText;
|
||||
if (styleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT) {
|
||||
aAlign.mXOffset += remainingSpace;
|
||||
} else if (styleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER) {
|
||||
aAlign.mXOffset += remainingSpace / 2;
|
||||
} else {
|
||||
// If we don't have a special text-align value indicating
|
||||
// HTML alignment, then use the CSS rules.
|
||||
|
||||
// When neither margin is auto then the block is said to
|
||||
// be over constrained, Depending on the direction, choose
|
||||
// which margin to treat as auto.
|
||||
PRUint8 direction = mOuterReflowState.mStyleVisibility->mDirection;
|
||||
if (NS_STYLE_DIRECTION_RTL == direction) {
|
||||
// The left margin becomes auto
|
||||
aAlign.mXOffset += remainingSpace;
|
||||
}
|
||||
//else {
|
||||
// The right margin becomes auto which is a no-op
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ComputeShrinkwrapMargins(const nsStyleMargin* aStyleMargin, nscoord aWidth,
|
||||
nsMargin& aMargin, nscoord& aXToUpdate)
|
||||
{
|
||||
nscoord boxWidth = aWidth;
|
||||
float leftPct = 0.0, rightPct = 0.0;
|
||||
const nsStyleSides& margin = aStyleMargin->mMargin;
|
||||
|
||||
if (eStyleUnit_Percent == margin.GetLeftUnit()) {
|
||||
nsStyleCoord coord;
|
||||
leftPct = margin.GetLeft(coord).GetPercentValue();
|
||||
} else {
|
||||
boxWidth += aMargin.left;
|
||||
}
|
||||
|
||||
if (eStyleUnit_Percent == margin.GetRightUnit()) {
|
||||
nsStyleCoord coord;
|
||||
rightPct = margin.GetRight(coord).GetPercentValue();
|
||||
} else {
|
||||
boxWidth += aMargin.right;
|
||||
}
|
||||
|
||||
// The total shrink wrap width "sww" (i.e., the width that the
|
||||
// containing block needs to be to shrink-wrap this block) is
|
||||
// calculated by the expression:
|
||||
// sww = bw + (mp * sww)
|
||||
// where "bw" is the box width (frame width plus margins that aren't
|
||||
// percentage based) and "mp" are the total margin percentages (i.e.,
|
||||
// the left percentage value plus the right percentage value).
|
||||
// Solving for "sww" gives:
|
||||
// sww = bw / (1 - mp)
|
||||
// Note that this is only well defined for "mp" less than 100% and
|
||||
// greater than -100% (XXXldb but we only accept 0 to 100%).
|
||||
|
||||
float marginPct = leftPct + rightPct;
|
||||
if (marginPct >= 1.0) {
|
||||
// Ignore the right percentage and just use the left percentage
|
||||
// XXX Pay attention to direction property...
|
||||
marginPct = leftPct;
|
||||
rightPct = 0.0;
|
||||
}
|
||||
|
||||
if ((marginPct > 0.0) && (marginPct < 1.0)) {
|
||||
double shrinkWrapWidth = float(boxWidth) / (1.0 - marginPct);
|
||||
|
||||
if (eStyleUnit_Percent == margin.GetLeftUnit()) {
|
||||
aMargin.left = NSToCoordFloor((float)(shrinkWrapWidth * leftPct));
|
||||
aXToUpdate += aMargin.left;
|
||||
}
|
||||
if (eStyleUnit_Percent == margin.GetRightUnit()) {
|
||||
aMargin.right = NSToCoordFloor((float)(shrinkWrapWidth * rightPct));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nsPointDtor(void *aFrame, nsIAtom *aPropertyName,
|
||||
void *aPropertyValue, void *aDtorData)
|
||||
{
|
||||
nsPoint *point = NS_STATIC_CAST(nsPoint*, aPropertyValue);
|
||||
delete point;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
PRBool aApplyTopMargin,
|
||||
nsCollapsingMargin& aPrevBottomMargin,
|
||||
PRBool aIsAdjacentWithTop,
|
||||
nsMargin& aComputedOffsets,
|
||||
nsHTMLReflowState& aFrameRS,
|
||||
nsReflowStatus& aFrameReflowStatus)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
mFrame = aFrameRS.frame;
|
||||
mSpace = aSpace;
|
||||
|
||||
// Get reflow reason set correctly. It's possible that a child was
|
||||
// created and then it was decided that it could not be reflowed
|
||||
// (for example, a block frame that isn't at the start of a
|
||||
// line). In this case the reason will be wrong so we need to check
|
||||
// the frame state.
|
||||
aFrameRS.reason = eReflowReason_Resize;
|
||||
if (NS_FRAME_FIRST_REFLOW & mFrame->GetStateBits()) {
|
||||
aFrameRS.reason = eReflowReason_Initial;
|
||||
}
|
||||
else if (mOuterReflowState.reason == eReflowReason_Incremental) {
|
||||
// If the frame we're about to reflow is on the reflow path, then
|
||||
// propagate the reflow as `incremental' so it unwinds correctly
|
||||
// to the target frames below us.
|
||||
PRBool frameIsOnReflowPath = mOuterReflowState.path->HasChild(mFrame);
|
||||
if (frameIsOnReflowPath)
|
||||
aFrameRS.reason = eReflowReason_Incremental;
|
||||
|
||||
// But...if the incremental reflow command is a StyleChanged
|
||||
// reflow and its target is the current block, change the reason
|
||||
// to `style change', so that it propagates through the entire
|
||||
// subtree.
|
||||
nsHTMLReflowCommand* rc = mOuterReflowState.path->mReflowCommand;
|
||||
if (rc) {
|
||||
nsReflowType type;
|
||||
rc->GetType(type);
|
||||
if (type == eReflowType_StyleChanged)
|
||||
aFrameRS.reason = eReflowReason_StyleChange;
|
||||
else if (type == eReflowType_ReflowDirty &&
|
||||
(mFrame->GetStateBits() & NS_FRAME_IS_DIRTY) &&
|
||||
!frameIsOnReflowPath) {
|
||||
aFrameRS.reason = eReflowReason_Dirty;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mOuterReflowState.reason == eReflowReason_StyleChange) {
|
||||
aFrameRS.reason = eReflowReason_StyleChange;
|
||||
}
|
||||
else if (mOuterReflowState.reason == eReflowReason_Dirty) {
|
||||
if (mFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
|
||||
aFrameRS.reason = eReflowReason_Dirty;
|
||||
}
|
||||
|
||||
/* We build a different reflow context based on the width attribute of the block,
|
||||
* if it's a float.
|
||||
* Auto-width floats need to have their containing-block size set explicitly,
|
||||
* factoring in other floats that impact it.
|
||||
* It's possible this should be quirks-only.
|
||||
* All other blocks proceed normally.
|
||||
*/
|
||||
// XXXldb We should really fix this in nsHTMLReflowState::InitConstraints instead.
|
||||
const nsStylePosition* position = mFrame->GetStylePosition();
|
||||
nsStyleUnit widthUnit = position->mWidth.GetUnit();
|
||||
const nsStyleDisplay* display = mFrame->GetStyleDisplay();
|
||||
|
||||
if ((eStyleUnit_Auto == widthUnit) &&
|
||||
((NS_STYLE_FLOAT_LEFT == display->mFloats) ||
|
||||
(NS_STYLE_FLOAT_RIGHT == display->mFloats))) {
|
||||
// Initialize the reflow state and constrain the containing block's
|
||||
// width and height to the available width and height.
|
||||
aFrameRS.Init(mPresContext, mSpace.width, mSpace.height);
|
||||
}
|
||||
else {
|
||||
// Initialize the reflow state and use the containing block's computed
|
||||
// width and height (or derive appropriate values for an
|
||||
// absolutely positioned frame).
|
||||
aFrameRS.Init(mPresContext);
|
||||
}
|
||||
|
||||
aComputedOffsets = aFrameRS.mComputedOffsets;
|
||||
if (NS_STYLE_POSITION_RELATIVE == display->mPosition) {
|
||||
nsPropertyTable *propTable = mPresContext->PropertyTable();
|
||||
|
||||
nsPoint *offsets = NS_STATIC_CAST(nsPoint*,
|
||||
propTable->GetProperty(mFrame, nsLayoutAtoms::computedOffsetProperty));
|
||||
|
||||
if (offsets)
|
||||
offsets->MoveTo(aComputedOffsets.left, aComputedOffsets.top);
|
||||
else {
|
||||
offsets = new nsPoint(aComputedOffsets.left, aComputedOffsets.top);
|
||||
if (offsets)
|
||||
propTable->SetProperty(mFrame, nsLayoutAtoms::computedOffsetProperty,
|
||||
offsets, nsPointDtor, nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
aFrameRS.mLineLayout = nsnull;
|
||||
if (!aIsAdjacentWithTop) {
|
||||
aFrameRS.mFlags.mIsTopOfPage = PR_FALSE; // make sure this is cleared
|
||||
}
|
||||
mComputedWidth = aFrameRS.mComputedWidth;
|
||||
|
||||
if (aApplyTopMargin) {
|
||||
// Compute the childs collapsed top margin (its margin collpased
|
||||
// with its first childs top-margin -- recursively).
|
||||
ComputeCollapsedTopMargin(mPresContext, aFrameRS, aPrevBottomMargin);
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, mOuterReflowState.frame);
|
||||
printf(": reflowing ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(" margin => %d\n", aPrevBottomMargin.get());
|
||||
#endif
|
||||
|
||||
// Adjust the available height if its constrained so that the
|
||||
// child frame doesn't think it can reflow into its margin area.
|
||||
if (NS_UNCONSTRAINEDSIZE != aFrameRS.availableHeight) {
|
||||
aFrameRS.availableHeight -= aPrevBottomMargin.get();
|
||||
}
|
||||
mTopMargin = aPrevBottomMargin;
|
||||
}
|
||||
|
||||
// Compute x/y coordinate where reflow will begin. Use the rules
|
||||
// from 10.3.3 to determine what to apply. At this point in the
|
||||
// reflow auto left/right margins will have a zero value.
|
||||
mMargin = aFrameRS.mComputedMargin;
|
||||
mStyleBorder = aFrameRS.mStyleBorder;
|
||||
mStyleMargin = aFrameRS.mStyleMargin;
|
||||
mStylePadding = aFrameRS.mStylePadding;
|
||||
nscoord x;
|
||||
nscoord y = mSpace.y + mTopMargin.get();
|
||||
|
||||
// If it's a right floated element, then calculate the x-offset
|
||||
// differently
|
||||
if (NS_STYLE_FLOAT_RIGHT == aFrameRS.mStyleDisplay->mFloats) {
|
||||
nscoord frameWidth;
|
||||
|
||||
if (NS_UNCONSTRAINEDSIZE == aFrameRS.mComputedWidth) {
|
||||
// Use the current frame width
|
||||
frameWidth = mFrame->GetSize().width;
|
||||
} else {
|
||||
frameWidth = aFrameRS.mComputedWidth +
|
||||
aFrameRS.mComputedBorderPadding.left +
|
||||
aFrameRS.mComputedBorderPadding.right;
|
||||
}
|
||||
|
||||
// if this is an unconstrained width reflow, then just place the float at the left margin
|
||||
if (NS_UNCONSTRAINEDSIZE == mSpace.width)
|
||||
x = mSpace.x;
|
||||
else
|
||||
x = mSpace.XMost() - mMargin.right - frameWidth;
|
||||
|
||||
} else {
|
||||
x = mSpace.x + mMargin.left;
|
||||
}
|
||||
mX = x;
|
||||
mY = y;
|
||||
|
||||
// If it's an auto-width table, then it doesn't behave like other blocks
|
||||
// XXX why not for a floating table too?
|
||||
if (aFrameRS.mStyleDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE &&
|
||||
!aFrameRS.mStyleDisplay->IsFloating()) {
|
||||
// If this isn't the table's initial reflow, then use its existing
|
||||
// width to determine where it will be placed horizontally
|
||||
if (aFrameRS.reason != eReflowReason_Initial) {
|
||||
nsBlockHorizontalAlign align;
|
||||
|
||||
align.mXOffset = x;
|
||||
AlignBlockHorizontally(mFrame->GetSize().width, align);
|
||||
// Don't reset "mX". because PlaceBlock() will recompute the
|
||||
// x-offset and expects "mX" to be at the left margin edge
|
||||
x = align.mXOffset;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the translation to be used for adjusting the spacemanagager
|
||||
// coordinate system for the frame. The spacemanager coordinates are
|
||||
// <b>inside</b> the callers border+padding, but the x/y coordinates
|
||||
// are not (recall that frame coordinates are relative to the parents
|
||||
// origin and that the parents border/padding is <b>inside</b> the
|
||||
// parent frame. Therefore we have to subtract out the parents
|
||||
// border+padding before translating.
|
||||
nscoord tx = x - mOuterReflowState.mComputedBorderPadding.left;
|
||||
nscoord ty = y - mOuterReflowState.mComputedBorderPadding.top;
|
||||
|
||||
// If the element is relatively positioned, then adjust x and y accordingly
|
||||
if (NS_STYLE_POSITION_RELATIVE == aFrameRS.mStyleDisplay->mPosition) {
|
||||
x += aFrameRS.mComputedOffsets.left;
|
||||
y += aFrameRS.mComputedOffsets.top;
|
||||
}
|
||||
|
||||
// Let frame know that we are reflowing it
|
||||
mFrame->WillReflow(mPresContext);
|
||||
|
||||
// Position it and its view (if it has one)
|
||||
// Note: Use "x" and "y" and not "mX" and "mY" because they more accurately
|
||||
// represents where we think the block will be placed
|
||||
mFrame->SetPosition(nsPoint(x, y));
|
||||
nsContainerFrame::PositionFrameView(mPresContext, mFrame);
|
||||
|
||||
#ifdef DEBUG
|
||||
mMetrics.width = nscoord(0xdeadbeef);
|
||||
mMetrics.height = nscoord(0xdeadbeef);
|
||||
mMetrics.ascent = nscoord(0xdeadbeef);
|
||||
mMetrics.descent = nscoord(0xdeadbeef);
|
||||
if (mMetrics.mComputeMEW) {
|
||||
mMetrics.mMaxElementWidth = nscoord(0xdeadbeef);
|
||||
}
|
||||
#endif
|
||||
|
||||
mOuterReflowState.mSpaceManager->Translate(tx, ty);
|
||||
|
||||
// See if this is the child's initial reflow and we are supposed to
|
||||
// compute our maximum width
|
||||
if (mComputeMaximumWidth && (eReflowReason_Initial == aFrameRS.reason)) {
|
||||
mOuterReflowState.mSpaceManager->PushState();
|
||||
|
||||
nscoord oldAvailableWidth = aFrameRS.availableWidth;
|
||||
nscoord oldComputedWidth = aFrameRS.mComputedWidth;
|
||||
|
||||
aFrameRS.availableWidth = NS_UNCONSTRAINEDSIZE;
|
||||
aFrameRS.mComputedWidth = NS_UNCONSTRAINEDSIZE;
|
||||
rv = mFrame->Reflow(mPresContext, mMetrics, aFrameRS, aFrameReflowStatus);
|
||||
|
||||
// Update the reflow metrics with the maximum width
|
||||
mMetrics.mMaximumWidth = mMetrics.width;
|
||||
#ifdef NOISY_REFLOW
|
||||
printf("*** nsBlockReflowContext::ReflowBlock block %p returning max width %d\n",
|
||||
mFrame, mMetrics.mMaximumWidth);
|
||||
#endif
|
||||
// The second reflow is just as a resize reflow with the constrained
|
||||
// width
|
||||
aFrameRS.availableWidth = oldAvailableWidth;
|
||||
aFrameRS.mComputedWidth = oldComputedWidth;
|
||||
aFrameRS.reason = eReflowReason_Resize;
|
||||
|
||||
mOuterReflowState.mSpaceManager->PopState();
|
||||
}
|
||||
|
||||
rv = mFrame->Reflow(mPresContext, mMetrics, aFrameRS, aFrameReflowStatus);
|
||||
mOuterReflowState.mSpaceManager->Translate(-tx, -ty);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) {
|
||||
if (CRAZY_WIDTH(mMetrics.width) || CRAZY_HEIGHT(mMetrics.height)) {
|
||||
printf("nsBlockReflowContext: ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(" metrics=%d,%d!\n", mMetrics.width, mMetrics.height);
|
||||
}
|
||||
if (mMetrics.mComputeMEW &&
|
||||
(nscoord(0xdeadbeef) == mMetrics.mMaxElementWidth)) {
|
||||
printf("nsBlockReflowContext: ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(" didn't set max-element-size!\n");
|
||||
}
|
||||
#ifdef REALLY_NOISY_MAX_ELEMENT_SIZE
|
||||
// Note: there are common reflow situations where this *correctly*
|
||||
// occurs; so only enable this debug noise when you really need to
|
||||
// analyze in detail.
|
||||
if (mMetrics.mComputeMEW &&
|
||||
(mMetrics.mMaxElementWidth > mMetrics.width)) {
|
||||
printf("nsBlockReflowContext: ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(": WARNING: maxElementWidth=%d > metrics=%d\n",
|
||||
mMetrics.mMaxElementWidth, mMetrics.width);
|
||||
}
|
||||
#endif
|
||||
if ((mMetrics.width == nscoord(0xdeadbeef)) ||
|
||||
(mMetrics.height == nscoord(0xdeadbeef)) ||
|
||||
(mMetrics.ascent == nscoord(0xdeadbeef)) ||
|
||||
(mMetrics.descent == nscoord(0xdeadbeef))) {
|
||||
printf("nsBlockReflowContext: ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(" didn't set whad %d,%d,%d,%d!\n",
|
||||
mMetrics.width, mMetrics.height,
|
||||
mMetrics.ascent, mMetrics.descent);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisyMaxElementWidth) {
|
||||
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) {
|
||||
if (mMetrics.mComputeMEW) {
|
||||
printf(" ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(": maxElementSize=%d wh=%d,%d\n",
|
||||
mMetrics.mMaxElementWidth,
|
||||
mMetrics.width, mMetrics.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(NS_FRAME_OUTSIDE_CHILDREN & mFrame->GetStateBits())) {
|
||||
// Provide overflow area for child that doesn't have any
|
||||
mMetrics.mOverflowArea.x = 0;
|
||||
mMetrics.mOverflowArea.y = 0;
|
||||
mMetrics.mOverflowArea.width = mMetrics.width;
|
||||
mMetrics.mOverflowArea.height = mMetrics.height;
|
||||
}
|
||||
|
||||
// Now that frame has been reflowed at least one time make sure that
|
||||
// the NS_FRAME_FIRST_REFLOW bit is cleared so that never give it an
|
||||
// initial reflow reason again.
|
||||
if (eReflowReason_Initial == aFrameRS.reason) {
|
||||
mFrame->RemoveStateBits(NS_FRAME_FIRST_REFLOW);
|
||||
}
|
||||
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus) ||
|
||||
(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
|
||||
// If frame is complete and has a next-in-flow, we need to delete
|
||||
// them now. Do not do this when a break-before is signaled because
|
||||
// the frame is going to get reflowed again (and may end up wanting
|
||||
// a next-in-flow where it ends up), unless it is an out of flow frame.
|
||||
if (NS_FRAME_IS_COMPLETE(aFrameReflowStatus)) {
|
||||
nsIFrame* kidNextInFlow = mFrame->GetNextInFlow();
|
||||
if (nsnull != kidNextInFlow) {
|
||||
// Remove all of the childs next-in-flows. Make sure that we ask
|
||||
// the right parent to do the removal (it's possible that the
|
||||
// parent is not this because we are executing pullup code)
|
||||
/* XXX promote DeleteChildsNextInFlow to nsIFrame to elminate this cast */
|
||||
NS_STATIC_CAST(nsHTMLContainerFrame*, kidNextInFlow->GetParent())
|
||||
->DeleteNextInFlowChild(mPresContext, kidNextInFlow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the block is shrink wrapping its width, then see if we have percentage
|
||||
// based margins. If so, we can calculate them now that we know the shrink
|
||||
// wrap width
|
||||
if (NS_SHRINKWRAPWIDTH == aFrameRS.mComputedWidth) {
|
||||
ComputeShrinkwrapMargins(aFrameRS.mStyleMargin, mMetrics.width, mMargin, mX);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to place the block frame within the available space. If
|
||||
* it fits, apply horizontal positioning (CSS 10.3.3), collapse
|
||||
* margins (CSS2 8.3.1). Also apply relative positioning.
|
||||
*/
|
||||
PRBool
|
||||
nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool aForceFit,
|
||||
const nsMargin& aComputedOffsets,
|
||||
nsCollapsingMargin& aBottomMarginResult,
|
||||
nsRect& aInFlowBounds,
|
||||
nsRect& aCombinedRect)
|
||||
{
|
||||
// Compute collapsed bottom margin value
|
||||
aBottomMarginResult = mMetrics.mCarriedOutBottomMargin;
|
||||
aBottomMarginResult.Include(mMargin.bottom);
|
||||
|
||||
// See if the block will fit in the available space
|
||||
PRBool fits = PR_TRUE;
|
||||
nscoord x = mX;
|
||||
nscoord y = mY;
|
||||
// When deciding whether it's empty we also need to take into
|
||||
// account the overflow area
|
||||
|
||||
// XXXldb What should really matter is whether there exist non-
|
||||
// empty frames in the block (with appropriate whitespace munging).
|
||||
// Consider the case where we clip off the overflow with
|
||||
// 'overflow: -moz-hidden-unscrollable' (which doesn't currently
|
||||
// affect mOverflowArea, but probably should.
|
||||
if ((0 == mMetrics.height) && (0 == mMetrics.mOverflowArea.height))
|
||||
{
|
||||
// Collapse the bottom margin with the top margin that was already
|
||||
// applied.
|
||||
aBottomMarginResult.Include(mTopMargin);
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
printf(" ");
|
||||
nsFrame::ListTag(stdout, mOuterReflowState.frame);
|
||||
printf(": ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n",
|
||||
y, mSpace.y);
|
||||
#endif
|
||||
|
||||
y = mSpace.y;
|
||||
|
||||
// Now place the frame and complete the reflow process
|
||||
nsContainerFrame::FinishReflowChild(mFrame, mPresContext, &aReflowState, mMetrics, x, y, 0);
|
||||
|
||||
// Empty blocks do not have anything special done to them and they
|
||||
// always fit. Note: don't force the width to 0
|
||||
aInFlowBounds = nsRect(x, y, mMetrics.width, 0);
|
||||
|
||||
// Retain combined area information in case we contain a float
|
||||
// and nothing else.
|
||||
aCombinedRect = mMetrics.mOverflowArea;
|
||||
aCombinedRect.x += x;
|
||||
aCombinedRect.y += y;
|
||||
}
|
||||
else {
|
||||
// See if the frame fit. If its the first frame then it always
|
||||
// fits.
|
||||
if (aForceFit || (y + mMetrics.height <= mSpace.YMost()))
|
||||
{
|
||||
// Calculate the actual x-offset and left and right margin
|
||||
nsBlockHorizontalAlign align;
|
||||
|
||||
align.mXOffset = x;
|
||||
AlignBlockHorizontally(mMetrics.width, align);
|
||||
x = align.mXOffset;
|
||||
mMargin.left = align.mLeftMargin;
|
||||
mMargin.right = align.mRightMargin;
|
||||
|
||||
// Update the in-flow bounds rectangle
|
||||
aInFlowBounds.SetRect(x, y,
|
||||
mMetrics.width,
|
||||
mMetrics.height);
|
||||
|
||||
// Apply CSS relative positioning to update x,y coordinates
|
||||
const nsStyleDisplay* styleDisp = mFrame->GetStyleDisplay();
|
||||
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
|
||||
x += aComputedOffsets.left;
|
||||
y += aComputedOffsets.top;
|
||||
}
|
||||
|
||||
// Compute combined-rect in callers coordinate system. The value
|
||||
// returned in the reflow metrics is relative to the child
|
||||
// frame. This includes relative positioning and the result should
|
||||
// be used only for painting and for 'overflow' handling.
|
||||
aCombinedRect.x = mMetrics.mOverflowArea.x + x;
|
||||
aCombinedRect.y = mMetrics.mOverflowArea.y + y;
|
||||
aCombinedRect.width = mMetrics.mOverflowArea.width;
|
||||
aCombinedRect.height = mMetrics.mOverflowArea.height;
|
||||
|
||||
// Now place the frame and complete the reflow process
|
||||
nsContainerFrame::FinishReflowChild(mFrame, mPresContext, &aReflowState, mMetrics, x, y, 0);
|
||||
|
||||
// Adjust the max-element-size in the metrics to take into
|
||||
// account the margins around the block element.
|
||||
// Do not allow auto margins to impact the max-element size
|
||||
// since they are springy and don't really count!
|
||||
if (mMetrics.mComputeMEW) {
|
||||
nsMargin maxElemMargin;
|
||||
const nsStyleSides &styleMargin = mStyleMargin->mMargin;
|
||||
nsStyleCoord coord;
|
||||
if (styleMargin.GetLeftUnit() == eStyleUnit_Coord)
|
||||
maxElemMargin.left = styleMargin.GetLeft(coord).GetCoordValue();
|
||||
else
|
||||
maxElemMargin.left = 0;
|
||||
if (styleMargin.GetRightUnit() == eStyleUnit_Coord)
|
||||
maxElemMargin.right = styleMargin.GetRight(coord).GetCoordValue();
|
||||
else
|
||||
maxElemMargin.right = 0;
|
||||
|
||||
nscoord dummyXOffset;
|
||||
// Base the margins on the max-element size
|
||||
ComputeShrinkwrapMargins(mStyleMargin, mMetrics.mMaxElementWidth,
|
||||
maxElemMargin, dummyXOffset);
|
||||
|
||||
mMetrics.mMaxElementWidth += maxElemMargin.left + maxElemMargin.right;
|
||||
}
|
||||
|
||||
// do the same for the maximum width
|
||||
if (mComputeMaximumWidth) {
|
||||
nsMargin maxWidthMargin;
|
||||
const nsStyleSides &styleMargin = mStyleMargin->mMargin;
|
||||
nsStyleCoord coord;
|
||||
if (styleMargin.GetLeftUnit() == eStyleUnit_Coord)
|
||||
maxWidthMargin.left = styleMargin.GetLeft(coord).GetCoordValue();
|
||||
else
|
||||
maxWidthMargin.left = 0;
|
||||
if (styleMargin.GetRightUnit() == eStyleUnit_Coord)
|
||||
maxWidthMargin.right = styleMargin.GetRight(coord).GetCoordValue();
|
||||
else
|
||||
maxWidthMargin.right = 0;
|
||||
|
||||
nscoord dummyXOffset;
|
||||
// Base the margins on the maximum width
|
||||
ComputeShrinkwrapMargins(mStyleMargin, mMetrics.mMaximumWidth,
|
||||
maxWidthMargin, dummyXOffset);
|
||||
|
||||
mMetrics.mMaximumWidth += maxWidthMargin.left + maxWidthMargin.right;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Send the DidReflow() notification, but don't bother placing
|
||||
// the frame
|
||||
mFrame->DidReflow(mPresContext, &aReflowState, NS_FRAME_REFLOW_FINISHED);
|
||||
fits = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return fits;
|
||||
}
|
|
@ -39,10 +39,12 @@
|
|||
#define nsBlockReflowContext_h___
|
||||
|
||||
#include "nsIFrame.h"
|
||||
#include "nsHTMLReflowState.h"
|
||||
#include "nsHTMLReflowMetrics.h"
|
||||
|
||||
class nsBlockFrame;
|
||||
class nsBlockReflowState;
|
||||
class nsHTMLReflowState;
|
||||
class nsLineBox;
|
||||
class nsIFrame;
|
||||
class nsPresContext;
|
||||
class nsLineLayout;
|
||||
|
@ -62,7 +64,8 @@ public:
|
|||
|
||||
nsresult ReflowBlock(const nsRect& aSpace,
|
||||
PRBool aApplyTopMargin,
|
||||
nsCollapsingMargin& aPrevBottomMargin,
|
||||
nsCollapsingMargin& aPrevMargin,
|
||||
nscoord aClearance,
|
||||
PRBool aIsAdjacentWithTop,
|
||||
nsMargin& aComputedOffsets,
|
||||
nsHTMLReflowState& aReflowState,
|
||||
|
@ -70,6 +73,7 @@ public:
|
|||
|
||||
PRBool PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool aForceFit,
|
||||
nsLineBox* aLine,
|
||||
const nsMargin& aComputedOffsets,
|
||||
nsCollapsingMargin& aBottomMarginResult /* out */,
|
||||
nsRect& aInFlowBounds,
|
||||
|
@ -101,9 +105,23 @@ public:
|
|||
return mMetrics.mMaximumWidth;
|
||||
}
|
||||
|
||||
static void ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
nsHTMLReflowState& aRS,
|
||||
/* inout */ nsCollapsingMargin& aMargin);
|
||||
/**
|
||||
* Computes the collapsed top margin for a block whose reflow state is in aRS.
|
||||
* The computed margin is added into aMargin.
|
||||
* If aClearanceFrame is null then this is the first optimistic pass which shall assume
|
||||
* that no frames have clearance, and we clear the HasClearance on all frames encountered.
|
||||
* If non-null, this is the second pass and
|
||||
* the caller has decided aClearanceFrame needs clearance (and we will
|
||||
* therefore stop collapsing there); also, this function is responsible for marking
|
||||
* it with SetHasClearance.
|
||||
* If in the optimistic pass any frame is encountered that might possibly need
|
||||
* clearance (i.e., if we really needed the optimism assumption) then we set aMayNeedRetry
|
||||
* to true.
|
||||
* We return PR_TRUE if we changed the clearance state of any line and marked it dirty.
|
||||
*/
|
||||
static PRBool ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
|
||||
nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame,
|
||||
PRBool* aMayNeedRetry);
|
||||
|
||||
protected:
|
||||
nsPresContext* mPresContext;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,268 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
* L. David Baron <dbaron@dbaron.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsBlockReflowState_h__
|
||||
#define nsBlockReflowState_h__
|
||||
|
||||
#include "nsBlockBandData.h"
|
||||
#include "nsLineBox.h"
|
||||
#include "nsFrameList.h"
|
||||
|
||||
class nsBlockFrame;
|
||||
|
||||
class nsBlockReflowState {
|
||||
public:
|
||||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
PRBool aBlockMarginRoot);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
/**
|
||||
* Get the available reflow space for the current y coordinate. The
|
||||
* available space is relative to our coordinate system (0,0) is our
|
||||
* upper left corner.
|
||||
*/
|
||||
void GetAvailableSpace() {
|
||||
GetAvailableSpace(mY);
|
||||
}
|
||||
|
||||
void GetAvailableSpace(nscoord aY);
|
||||
|
||||
void InitFloat(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
|
||||
void AddFloat(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
PRBool aInitialReflow,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
|
||||
PRBool CanPlaceFloat(const nsRect& aFloatRect, PRUint8 aFloats);
|
||||
|
||||
void FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
||||
PRBool* aIsLeftFloat,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
|
||||
PRBool PlaceBelowCurrentLineFloats(nsFloatCacheList& aFloats);
|
||||
|
||||
// called when clearing a line with a break type caused by a BR past
|
||||
// floats, and also used internally by ClearPastFloats
|
||||
void ClearFloats(nscoord aY, PRUint8 aBreakType);
|
||||
|
||||
// called when clearing a block past floats
|
||||
PRBool ClearPastFloats(PRUint8 aBreakType);
|
||||
|
||||
PRBool IsAdjacentWithTop() const {
|
||||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
}
|
||||
|
||||
const nsMargin& BorderPadding() const {
|
||||
return mReflowState.mComputedBorderPadding;
|
||||
}
|
||||
|
||||
const nsMargin& Margin() const {
|
||||
return mReflowState.mComputedMargin;
|
||||
}
|
||||
|
||||
void UpdateMaxElementWidth(nscoord aMaxElementWidth);
|
||||
|
||||
void UpdateMaximumWidth(nscoord aMaximumWidth);
|
||||
|
||||
// Reconstruct the previous bottom margin that goes above |aLine|.
|
||||
void ReconstructMarginAbove(nsLineList::iterator aLine);
|
||||
|
||||
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult);
|
||||
|
||||
protected:
|
||||
void RecoverFloats(nsLineList::iterator aLine, nscoord aDeltaY);
|
||||
|
||||
public:
|
||||
void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaY);
|
||||
|
||||
void AdvanceToNextLine() {
|
||||
mLineNumber++;
|
||||
}
|
||||
|
||||
PRBool IsImpactedByFloat() const;
|
||||
|
||||
nsLineBox* NewLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock);
|
||||
|
||||
void FreeLineBox(nsLineBox* aLine);
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is the "global" state computed once for the reflow of
|
||||
// the block.
|
||||
|
||||
// The block frame that is using this object
|
||||
nsBlockFrame* mBlock;
|
||||
|
||||
nsPresContext* mPresContext;
|
||||
|
||||
const nsHTMLReflowState& mReflowState;
|
||||
|
||||
nsSpaceManager* mSpaceManager;
|
||||
|
||||
// The coordinates within the spacemanager where the block is being
|
||||
// placed <b>after</b> taking into account the blocks border and
|
||||
// padding. This, therefore, represents the inner "content area" (in
|
||||
// spacemanager coordinates) where child frames will be placed,
|
||||
// including child blocks and floats.
|
||||
nscoord mSpaceManagerX, mSpaceManagerY;
|
||||
|
||||
// XXX get rid of this
|
||||
nsReflowStatus mReflowStatus;
|
||||
|
||||
nscoord mBottomEdge;
|
||||
|
||||
// The content area to reflow child frames within. The x/y
|
||||
// coordinates are known to be mBorderPadding.left and
|
||||
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
|
||||
// if the container reflowing this frame has given the frame an
|
||||
// unconstrained area.
|
||||
nsSize mContentArea;
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is "running" state updated by the reflow of each line
|
||||
// in the block. This same state is "recovered" when a line is not
|
||||
// dirty and is passed over during incremental reflow.
|
||||
|
||||
// The current line being reflowed
|
||||
// If it is mBlock->end_lines(), then it is invalid.
|
||||
nsLineList::iterator mCurrentLine;
|
||||
|
||||
// The current Y coordinate in the block
|
||||
nscoord mY;
|
||||
|
||||
// The available space within the current band.
|
||||
nsRect mAvailSpaceRect;
|
||||
|
||||
// The maximum x-most of each line
|
||||
nscoord mKidXMost;
|
||||
|
||||
// The combined area of all floats placed so far
|
||||
nsRect mFloatCombinedArea;
|
||||
|
||||
nsFloatCacheFreeList mFloatCacheFreeList;
|
||||
|
||||
// Previous child. This is used when pulling up a frame to update
|
||||
// the sibling list.
|
||||
nsIFrame* mPrevChild;
|
||||
|
||||
// The previous child frames collapsed bottom margin value.
|
||||
nsCollapsingMargin mPrevBottomMargin;
|
||||
|
||||
// The current next-in-flow for the block. When lines are pulled
|
||||
// from a next-in-flow, this is used to know which next-in-flow to
|
||||
// pull from. When a next-in-flow is emptied of lines, we advance
|
||||
// this to the next next-in-flow.
|
||||
nsBlockFrame* mNextInFlow;
|
||||
|
||||
// The current band data for the current Y coordinate
|
||||
nsBlockBandData mBand;
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// Temporary line-reflow state. This state is used during the reflow
|
||||
// of a given line, but doesn't have meaning before or after.
|
||||
|
||||
// The list of floats that are "current-line" floats. These are
|
||||
// added to the line after the line has been reflowed, to keep the
|
||||
// list fiddling from being N^2.
|
||||
nsFloatCacheFreeList mCurrentLineFloats;
|
||||
|
||||
// The list of floats which are "below current-line"
|
||||
// floats. These are reflowed/placed after the line is reflowed
|
||||
// and placed. Again, this is done to keep the list fiddling from
|
||||
// being N^2.
|
||||
nsFloatCacheFreeList mBelowCurrentLineFloats;
|
||||
|
||||
nscoord mMaxElementWidth;
|
||||
nscoord mMaximumWidth;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
|
||||
// block reflow state flags
|
||||
#define BRS_UNCONSTRAINEDWIDTH 0x00000001
|
||||
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
||||
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
||||
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
||||
#define BRS_ISTOPMARGINROOT 0x00000020 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000040
|
||||
#define BRS_APPLYTOPMARGIN 0x00000080 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTWIDTH 0x00000100
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000200
|
||||
#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH
|
||||
|
||||
PRInt16 mFlags;
|
||||
|
||||
PRUint8 mFloatBreakType;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // nsBlockReflowState_h__
|
|
@ -111,6 +111,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mSpecialHeightReflow = PR_FALSE;
|
||||
mFlags.mIsTopOfPage = PR_FALSE;
|
||||
mFlags.mNextInFlowUntouched = PR_FALSE;
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = nsnull;
|
||||
mPercentHeightReflowInitiator = nsnull;
|
||||
Init(aPresContext);
|
||||
|
@ -143,6 +145,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mSpecialHeightReflow = PR_FALSE;
|
||||
mFlags.mIsTopOfPage = PR_FALSE;
|
||||
mFlags.mNextInFlowUntouched = PR_FALSE;
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = nsnull;
|
||||
mPercentHeightReflowInitiator = nsnull;
|
||||
Init(aPresContext);
|
||||
|
@ -193,6 +197,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
|
@ -240,6 +246,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
|
@ -287,6 +295,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
|||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче