pjs/layout/generic/nsBlockFrame.h

618 строки
24 KiB
C++

/* -*- 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();
// 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___ */