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:
roc+%cs.cmu.edu 2004-11-25 14:51:00 +00:00
Родитель fc246c8217
Коммит fcfeb6506e
28 изменённых файлов: 1522 добавлений и 9552 удалений

Просмотреть файл

@ -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;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу