From 599a640cff6553daf38b1a3c101e6b16d83cadc5 Mon Sep 17 00:00:00 2001 From: "waterson%netscape.com" Date: Tue, 1 May 2001 03:41:11 +0000 Subject: [PATCH] Remove everything but nsBlockReflowStat implementation, part 1. Not part of the build. --- layout/generic/nsBlockReflowState.cpp | 1732 ------------------- layout/html/base/src/nsBlockReflowState.cpp | 1732 ------------------- 2 files changed, 3464 deletions(-) diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index bbba65921ec..7791d909025 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -22,571 +22,6 @@ * Robert O'Callahan * L. David Baron */ -#include "nsCOMPtr.h" -#include "nsBlockFrame.h" -#include "nsBlockReflowContext.h" -#include "nsBlockBandData.h" -#include "nsBulletFrame.h" -#include "nsLineBox.h" -#include "nsInlineFrame.h" -#include "nsLineLayout.h" -#include "nsPlaceholderFrame.h" -#include "nsStyleConsts.h" -#include "nsHTMLIIDs.h" -#include "nsCSSRendering.h" -#include "nsIFrameManager.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsIReflowCommand.h" -#include "nsISpaceManager.h" -#include "nsIStyleContext.h" -#include "nsIView.h" -#include "nsIFontMetrics.h" -#include "nsHTMLParts.h" -#include "nsHTMLAtoms.h" -#include "nsHTMLValue.h" -#include "nsIDOMEvent.h" -#include "nsIHTMLContent.h" -#include "prprf.h" -#include "nsLayoutAtoms.h" -#include "nsITextContent.h" -#include "nsStyleChangeList.h" -#include "nsISizeOfHandler.h" -#include "nsIFocusTracker.h" -#include "nsIFrameSelection.h" -#include "nsSpaceManager.h" -#include "prenv.h" -#include "plstr.h" - -#ifdef IBMBIDI -#include "nsBidiPresUtils.h" -#endif // IBMBIDI - -#include "nsIDOMHTMLBodyElement.h" -#include "nsIDOMHTMLHtmlElement.h" - -#ifdef DEBUG - -static PRBool gLamePaintMetrics; -static PRBool gLameReflowMetrics; -static PRBool gNoisy; -static PRBool gNoisyDamageRepair; -static PRBool gNoisyMaxElementSize; -static PRBool gNoisyReflow; -static PRBool gReallyNoisyReflow; -static PRBool gNoisySpaceManager; -static PRBool gVerifyLines; -static PRBool gDisableResizeOpt; - -struct BlockDebugFlags { - const char* name; - PRBool* on; -}; - -static BlockDebugFlags gFlags[] = { - { "reflow", &gNoisyReflow }, - { "really-noisy-reflow", &gReallyNoisyReflow }, - { "max-element-size", &gNoisyMaxElementSize }, - { "space-manager", &gNoisySpaceManager }, - { "verify-lines", &gVerifyLines }, - { "damage-repair", &gNoisyDamageRepair }, - { "lame-paint-metrics", &gLamePaintMetrics }, - { "lame-reflow-metrics", &gLameReflowMetrics }, - { "disable-resize-opt", &gDisableResizeOpt }, -}; -#define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0])) - -static void -ShowDebugFlags() -{ - printf("Here are the available GECKO_BLOCK_DEBUG_FLAGS:\n"); - BlockDebugFlags* bdf = gFlags; - BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS; - for (; bdf < end; bdf++) { - printf(" %s\n", bdf->name); - } - printf("Note: GECKO_BLOCK_DEBUG_FLAGS is a comma seperated list of flag\n"); - printf("names (no whitespace)\n"); -} - -static void -InitDebugFlags() -{ - static PRBool firstTime = PR_TRUE; - if (firstTime) { - firstTime = PR_FALSE; - char* flags = PR_GetEnv("GECKO_BLOCK_DEBUG_FLAGS"); - if (flags) { - PRBool error = PR_FALSE; - for (;;) { - char* cm = PL_strchr(flags, ','); - if (cm) *cm = '\0'; - - PRBool found = PR_FALSE; - BlockDebugFlags* bdf = gFlags; - BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS; - for (; bdf < end; bdf++) { - if (PL_strcasecmp(bdf->name, flags) == 0) { - *(bdf->on) = PR_TRUE; - printf("nsBlockFrame: setting %s debug flag on\n", bdf->name); - gNoisy = PR_TRUE; - found = PR_TRUE; - break; - } - } - if (!found) { - error = PR_TRUE; - } - - if (!cm) break; - *cm = ','; - flags = cm + 1; - } - if (error) { - ShowDebugFlags(); - } - } - } -} - -#undef NOISY_FIRST_LINE // enables debug output for first-line specific layout -#undef REALLY_NOISY_FIRST_LINE // enables extra debug output for first-line specific layout -#undef NOISY_FIRST_LETTER // enables debug output for first-letter specific layout -#undef NOISY_MAX_ELEMENT_SIZE // enables debug output for max element size computation -#undef NOISY_MAXIMUM_WIDTH // enables debug output for max width computation -#undef NOISY_KIDXMOST // enables debug output for aState.mKidXMost computation -#undef NOISY_FLOATER // enables debug output for floater reflow (the in/out metrics for the floated block) -#undef NOISY_FLOATER_CLEARING -#undef NOISY_FINAL_SIZE // enables debug output for desired width/height computation, once all children have been reflowed -#undef NOISY_REMOVE_FRAME -#undef NOISY_COMBINED_AREA // enables debug output for combined area computation -#undef NOISY_VERTICAL_MARGINS -#undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested -#undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete" -#undef NOISY_SPACEMANAGER // enables debug output for space manager use, useful for analysing reflow of floaters and positioned elements -#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate -#undef REALLY_NOISY_REFLOW // some extra debug info - -#endif - -#define FIX_BUG_38157 -#define FIX_BUG_37657 - -// add in a sanity check for absurdly deep frame trees. See bug 42138 -// can't just use IsFrameTreeTooDeep() because that method has side effects we don't want -#define MAX_DEPTH_FOR_LIST_RENUMBERING 200 // 200 open displayable tags is pretty unrealistic - -//---------------------------------------------------------------------- - -// Debugging support code - -#ifdef DEBUG -static PRInt32 gNoiseIndent; -static const char* kReflowCommandType[] = { - "ContentChanged", - "StyleChanged", - "PullupReflow", - "PushReflow", - "CheckPullupReflow", - "ReflowDirty", - "UserDefined", -}; -#endif - -#ifdef REALLY_NOISY_FIRST_LINE -static void -DumpStyleGeneaology(nsIFrame* aFrame, const char* gap) -{ - fputs(gap, stdout); - nsFrame::ListTag(stdout, aFrame); - printf(": "); - nsIStyleContext* sc; - aFrame->GetStyleContext(&sc); - while (nsnull != sc) { - nsIStyleContext* psc; - printf("%p ", sc); - psc = sc->GetParent(); - NS_RELEASE(sc); - sc = psc; - } - printf("\n"); -} -#endif - -#ifdef REFLOW_STATUS_COVERAGE -static void -RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus) -{ - static PRUint32 record[2]; - - // 0: child-is-block - // 1: child-is-inline - PRIntn index = 0; - if (!aChildIsBlock) index |= 1; - - // Compute new status - PRUint32 newS = record[index]; - if (NS_INLINE_IS_BREAK(aFrameReflowStatus)) { - if (NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) { - newS |= 1; - } - else if (NS_FRAME_IS_NOT_COMPLETE(aFrameReflowStatus)) { - newS |= 2; - } - else { - newS |= 4; - } - } - else if (NS_FRAME_IS_NOT_COMPLETE(aFrameReflowStatus)) { - newS |= 8; - } - else { - newS |= 16; - } - - // Log updates to the status that yield different values - if (record[index] != newS) { - record[index] = newS; - printf("record(%d): %02x %02x\n", index, record[0], record[1]); - } -} -#endif - -//---------------------------------------------------------------------- - -inline void CombineRects(const nsRect& r1, nsRect& r2) -{ - nscoord xa = r2.x; - nscoord ya = r2.y; - nscoord xb = xa + r2.width; - nscoord yb = ya + r2.height; - nscoord x = r1.x; - nscoord y = r1.y; - nscoord xmost = x + r1.width; - nscoord ymost = y + r1.height; - if (x < xa) { - xa = x; - } - if (xmost > xb) { - xb = xmost; - } - if (y < ya) { - ya = y; - } - if (ymost > yb) { - yb = ymost; - } - r2.x = xa; - r2.y = ya; - r2.width = xb - xa; - r2.height = yb - ya; -} - -//---------------------------------------------------------------------- - -class nsBlockReflowState { -public: - nsBlockReflowState(const nsHTMLReflowState& aReflowState, - nsIPresContext* aPresContext, - nsBlockFrame* aFrame, - const nsHTMLReflowMetrics& aMetrics, - PRBool aBlockMarginRoot); - - ~nsBlockReflowState(); - - /** - * Update our state when aLine is skipped over during incremental - * reflow. - */ - void RecoverStateFrom(nsLineBox* aLine, PRBool aPrevLineWasClean); - - /** - * 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) { -#ifdef DEBUG - // Verify that the caller setup the coordinate system properly - nscoord wx, wy; - mSpaceManager->GetTranslation(wx, wy); - NS_ASSERTION((wx == mSpaceManagerX) && (wy == mSpaceManagerY), - "bad coord system"); -#endif - - mBand.GetAvailableSpace(aY - BorderPadding().top, mAvailSpaceRect); - -#ifdef DEBUG - if (gNoisyReflow) { - nsFrame::IndentBy(stdout, gNoiseIndent); - printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n", - mAvailSpaceRect.x, mAvailSpaceRect.y, - mAvailSpaceRect.width, mAvailSpaceRect.height, - mBand.GetTrapezoidCount()); - } -#endif - } - - void InitFloater(nsLineLayout& aLineLayout, - nsPlaceholderFrame* aPlaceholderFrame); - - void AddFloater(nsLineLayout& aLineLayout, - nsPlaceholderFrame* aPlaceholderFrame, - PRBool aInitialReflow); - - PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats); - - void PlaceFloater(nsFloaterCache* aFloaterCache, - PRBool* aIsLeftFloater); - - void PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aFloaters); - - void ClearFloaters(nscoord aY, PRUint8 aBreakType); - - PRBool ClearPastFloaters(PRUint8 aBreakType); - - PRBool IsLeftMostChild(nsIPresContext* aPresContext, nsIFrame* aFrame); - - PRBool IsAdjacentWithTop() const { - return mY == mReflowState.mComputedBorderPadding.top; - } - - const nsMargin& BorderPadding() const { - return mReflowState.mComputedBorderPadding; - } - - const nsMargin& Margin() const { - return mReflowState.mComputedMargin; - } - - void UpdateMaxElementSize(const nsSize& aMaxElementSize) { -#ifdef NOISY_MAX_ELEMENT_SIZE - nsSize oldSize = mMaxElementSize; -#endif - if (aMaxElementSize.width > mMaxElementSize.width) { - mMaxElementSize.width = aMaxElementSize.width; - } - if (aMaxElementSize.height > mMaxElementSize.height) { - mMaxElementSize.height = aMaxElementSize.height; - } -#ifdef NOISY_MAX_ELEMENT_SIZE - if ((mMaxElementSize.width != oldSize.width) || - (mMaxElementSize.height != oldSize.height)) { - nsFrame::IndentBy(stdout, mBlock->GetDepth()); - if (NS_UNCONSTRAINEDSIZE == mReflowState.availableWidth) { - printf("PASS1 "); - } - nsFrame::ListTag(stdout, mBlock); - printf(": old max-element-size=%d,%d new=%d,%d\n", - oldSize.width, oldSize.height, - mMaxElementSize.width, mMaxElementSize.height); - } -#endif - } - - void UpdateMaximumWidth(nscoord aMaximumWidth) { - if (aMaximumWidth > mMaximumWidth) { -#ifdef NOISY_MAXIMUM_WIDTH - printf("nsBlockReflowState::UpdateMaximumWidth block %p caching max width %d\n", mBlock, aMaximumWidth); -#endif - mMaximumWidth = aMaximumWidth; - } - } - - void RecoverVerticalMargins(nsLineBox* aLine, - PRBool aApplyTopMargin, - nscoord* aTopMarginResult, - nscoord* aBottomMarginResult); - - void ComputeBlockAvailSpace(nsIFrame* aFrame, - nsSplittableType aSplitType, - const nsStyleDisplay* aDisplay, - nsRect& aResult); - - void RecoverStateFrom(nsLineBox* aLine, - PRBool aApplyTopMargin, - nsRect* aDamageRect); - - void AdvanceToNextLine() { - mLineNumber++; - } - - PRBool IsImpactedByFloater() { -#ifdef REALLY_NOISY_REFLOW - printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n", - this, mBand.GetFloaterCount()); -#endif - return mBand.GetFloaterCount(); - } - - nsLineBox* NewLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock); - - void FreeLineBox(nsLineBox* aLine); - - void StoreMaxElementSize(nsIFrame* aFloater, const nsSize& aSize) { - mBand.StoreMaxElementSize(mPresContext, aFloater, aSize); - } - - //---------------------------------------- - - // This state is the "global" state computed once for the reflow of - // the block. - - // The block frame that is using this object - nsBlockFrame* mBlock; - - nsIPresContext* mPresContext; - - const nsHTMLReflowState& mReflowState; - - nsISpaceManager* mSpaceManager; - - // The coordinates within the spacemanager where the block is being - // placed after 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 floaters. - 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 - nsLineBox* mCurrentLine; - - // The previous line just reflowed - nsLineBox* mPrevLine; - - // 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 floaters placed so far - nsRect mFloaterCombinedArea; - - // For unconstained-width reflow, we keep the right floaters - // combined area stored seperately. - PRBool mHaveRightFloaters; - nsRect mRightFloaterCombinedArea; - - nsFloaterCacheFreeList mFloaterCacheFreeList; - - // Previous child. This is used when pulling up a frame to update - // the sibling list. - nsIFrame* mPrevChild; - - // The next immediate child frame that is the target of an - // incremental reflow command. Once that child has been reflowed we - // null this slot out. - nsIFrame* mNextRCFrame; - - // The previous child frames collapsed bottom margin value. - nscoord 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 floaters that are "current-line" floaters. These are - // added to the line after the line has been reflowed, to keep the - // list fiddling from being N^2. - nsFloaterCacheFreeList mCurrentLineFloaters; - - // The list of floaters which are "below current-line" - // floaters. These are reflowed/placed after the line is reflowed - // and placed. Again, this is done to keep the list fiddling from - // being N^2. - nsFloaterCacheFreeList mBelowCurrentLineFloaters; - - nsSize mMaxElementSize; - 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_ISINLINEINCRREFLOW 0x00000010 -#define BRS_NOWRAP 0x00000020 -#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing? -#define BRS_ISBOTTOMMARGINROOT 0x00000080 -#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin -#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200 -#define BRS_COMPUTEMAXWIDTH 0x00000400 -#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH - - PRInt16 mFlags; - - 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; - } -}; - -// XXX This is vile. Make it go away -void -nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame) -{ - mBlockRS->InitFloater(*this, aFrame); -} -void -nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) -{ - mBlockRS->AddFloater(*this, aFrame, PR_FALSE); -} //---------------------------------------------------------------------- @@ -6287,1170 +5722,3 @@ nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType) } #endif } - -////////////////////////////////////////////////////////////////////// -// Painting, event handling - -PRIntn -nsBlockFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_TOP; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_BOTTOM; - } - return skip; -} - -#ifdef DEBUG -static void ComputeCombinedArea(nsLineBox* aLine, - nscoord aWidth, nscoord aHeight, - nsRect& aResult) -{ - nscoord xa = 0, ya = 0, xb = aWidth, yb = aHeight; - while (nsnull != aLine) { - // Compute min and max x/y values for the reflowed frame's - // combined areas - nsRect lineCombinedArea; - aLine->GetCombinedArea(&lineCombinedArea); - nscoord x = lineCombinedArea.x; - nscoord y = lineCombinedArea.y; - nscoord xmost = x + lineCombinedArea.width; - nscoord ymost = y + lineCombinedArea.height; - if (x < xa) { - xa = x; - } - if (xmost > xb) { - xb = xmost; - } - if (y < ya) { - ya = y; - } - if (ymost > yb) { - yb = ymost; - } - aLine = aLine->mNext; - } - - aResult.x = xa; - aResult.y = ya; - aResult.width = xb - xa; - aResult.height = yb - ya; -} -#endif - -NS_IMETHODIMP -nsBlockFrame::IsVisibleForPainting(nsIPresContext * aPresContext, - nsIRenderingContext& aRenderingContext, - PRBool aCheckVis, - PRBool* aIsVisible) -{ - // first check to see if we are visible - if (aCheckVis) { - const nsStyleDisplay* disp = (const nsStyleDisplay*)((nsIStyleContext*)mStyleContext)->GetStyleData(eStyleStruct_Display); - if (!disp->IsVisible()) { - *aIsVisible = PR_FALSE; - return NS_OK; - } - } - - // Start by assuming we are visible and need to be painted - *aIsVisible = PR_TRUE; - - // NOTE: GetSelectionforVisCheck checks the pagination to make sure we are printing - // In otherwords, the selection will ALWAYS be null if we are not printing, meaning - // the visibility will be TRUE in that case - nsCOMPtr selection; - nsresult rv = GetSelectionForVisCheck(aPresContext, getter_AddRefs(selection)); - if (NS_SUCCEEDED(rv) && selection) { - nsCOMPtr node(do_QueryInterface(mContent)); - - nsCOMPtr html(do_QueryInterface(mContent)); - nsCOMPtr body(do_QueryInterface(mContent)); - - if (!html && !body) { - rv = selection->ContainsNode(node, PR_TRUE, aIsVisible); - } - } - - return rv; -} - -NS_IMETHODIMP -nsBlockFrame::Paint(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nsFramePaintLayer aWhichLayer) -{ - if (NS_FRAME_IS_UNFLOWABLE & mState) { - return NS_OK; - } - -#ifdef DEBUG - if (gNoisyDamageRepair) { - if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { - PRInt32 depth = GetDepth(); - nsRect ca; - ComputeCombinedArea(mLines, mRect.width, mRect.height, ca); - nsFrame::IndentBy(stdout, depth); - ListTag(stdout); - printf(": bounds=%d,%d,%d,%d dirty=%d,%d,%d,%d ca=%d,%d,%d,%d\n", - mRect.x, mRect.y, mRect.width, mRect.height, - aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height, - ca.x, ca.y, ca.width, ca.height); - } - } -#endif - - PRBool isVisible; - if (NS_FAILED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible))) { - return NS_ERROR_FAILURE; - } - - // Only paint the border and background if we're visible - if (isVisible && (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) && - (0 != mRect.width) && (0 != mRect.height)) { - PRIntn skipSides = GetSkipSides(); - const nsStyleColor* color = (const nsStyleColor*) - mStyleContext->GetStyleData(eStyleStruct_Color); - const nsStyleBorder* border = (const nsStyleBorder*) - mStyleContext->GetStyleData(eStyleStruct_Border); - const nsStyleOutline* outline = (const nsStyleOutline*) - mStyleContext->GetStyleData(eStyleStruct_Outline); - - // Paint background, border and outline - nsRect rect(0, 0, mRect.width, mRect.height); - nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *color, *border, 0, 0); - nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *border, mStyleContext, - skipSides); - nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *border, *outline, mStyleContext, 0); - } - - PRBool paintingSuppressed = PR_FALSE; - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - shell->IsPaintingSuppressed(&paintingSuppressed); - if (paintingSuppressed) - return NS_OK; - - const nsStyleDisplay* disp = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - - // If overflow is hidden then set the clip rect so that children don't - // leak out of us. Note that because overflow'-clip' only applies to - // the content area we do this after painting the border and background - if (NS_STYLE_OVERFLOW_HIDDEN == disp->mOverflow) { - aRenderingContext.PushState(); - SetOverflowClipRect(aRenderingContext); - } - - // Child elements have the opportunity to override the visibility - // property and display even if the parent is hidden - if (NS_FRAME_PAINT_LAYER_FLOATERS == aWhichLayer) { - PaintFloaters(aPresContext, aRenderingContext, aDirtyRect); - } - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); - - if (NS_STYLE_OVERFLOW_HIDDEN == disp->mOverflow) { - PRBool clipState; - aRenderingContext.PopState(clipState); - } - -#if 0 - if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) { - // Render the bands in the spacemanager - nsISpaceManager* sm = mSpaceManager; - - if (nsnull != sm) { - nsBlockBandData band; - band.Init(sm, nsSize(mRect.width, mRect.height)); - nscoord y = 0; - while (y < mRect.height) { - nsRect availArea; - band.GetAvailableSpace(y, availArea); - - // Render a box and a diagonal line through the band - aRenderingContext.SetColor(NS_RGB(0,255,0)); - aRenderingContext.DrawRect(0, availArea.y, - mRect.width, availArea.height); - aRenderingContext.DrawLine(0, availArea.y, - mRect.width, availArea.YMost()); - - // Render boxes and opposite diagonal lines around the - // unavailable parts of the band. - PRInt32 i; - for (i = 0; i < band.GetTrapezoidCount(); i++) { - const nsBandTrapezoid* trapezoid = band.GetTrapezoid(i); - if (nsBandTrapezoid::Available != trapezoid->mState) { - nsRect r; - trapezoid->GetRect(r); - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) { - aRenderingContext.SetColor(NS_RGB(0,255,128)); - } - else { - aRenderingContext.SetColor(NS_RGB(128,255,0)); - } - aRenderingContext.DrawRect(r); - aRenderingContext.DrawLine(r.x, r.YMost(), r.XMost(), r.y); - } - } - y = availArea.YMost(); - } - } - } -#endif - - return NS_OK; -} - -void -nsBlockFrame::PaintFloaters(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect) -{ - for (nsLineBox* line = mLines; nsnull != line; line = line->mNext) { - if (!line->HasFloaters()) { - continue; - } - nsFloaterCache* fc = line->GetFirstFloater(); - while (fc) { - nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame(); - PaintChild(aPresContext, aRenderingContext, aDirtyRect, - floater, NS_FRAME_PAINT_LAYER_BACKGROUND); - PaintChild(aPresContext, aRenderingContext, aDirtyRect, - floater, NS_FRAME_PAINT_LAYER_FLOATERS); - PaintChild(aPresContext, aRenderingContext, aDirtyRect, - floater, NS_FRAME_PAINT_LAYER_FOREGROUND); - fc = fc->Next(); - } - } -} - -void -nsBlockFrame::PaintChildren(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nsFramePaintLayer aWhichLayer) -{ -#ifdef DEBUG - PRInt32 depth = 0; - if (gNoisyDamageRepair) { - if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { - depth = GetDepth(); - } - } - PRTime start = LL_ZERO; // Initialize these variables to silence the compiler. - PRInt32 drawnLines = 0; // They will only be used if set (gLamePaintMetrics). - if (gLamePaintMetrics) { - start = PR_Now(); - drawnLines = 0; - } -#endif - - for (nsLineBox* line = mLines; nsnull != line; line = line->mNext) { - // If the line's combined area (which includes child frames that - // stick outside of the line's bounding box or our bounding box) - // intersects the dirty rect then paint the line. - if (line->CombinedAreaIntersects(aDirtyRect)) { -#ifdef DEBUG - if (gNoisyDamageRepair && - (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) { - nsRect lineCombinedArea; - line->GetCombinedArea(&lineCombinedArea); - nsFrame::IndentBy(stdout, depth+1); - printf("draw line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n", - line, line->mBounds.x, line->mBounds.y, - line->mBounds.width, line->mBounds.height, - lineCombinedArea.x, lineCombinedArea.y, - lineCombinedArea.width, lineCombinedArea.height); - } - if (gLamePaintMetrics) { - drawnLines++; - } -#endif - nsIFrame* kid = line->mFirstChild; - PRInt32 n = line->GetChildCount(); - while (--n >= 0) { - PaintChild(aPresContext, aRenderingContext, aDirtyRect, kid, - aWhichLayer); - kid->GetNextSibling(&kid); - } - } -#ifdef DEBUG - else { - if (gNoisyDamageRepair && - (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) { - nsRect lineCombinedArea; - line->GetCombinedArea(&lineCombinedArea); - nsFrame::IndentBy(stdout, depth+1); - printf("skip line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n", - line, line->mBounds.x, line->mBounds.y, - line->mBounds.width, line->mBounds.height, - lineCombinedArea.x, lineCombinedArea.y, - lineCombinedArea.width, lineCombinedArea.height); - } - } -#endif - } - - if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { - if ((nsnull != mBullet) && HaveOutsideBullet()) { - // Paint outside bullets manually - PaintChild(aPresContext, aRenderingContext, aDirtyRect, mBullet, - aWhichLayer); - } - } - -#ifdef DEBUG - if (gLamePaintMetrics) { - PRTime end = PR_Now(); - - PRInt32 numLines = nsLineBox::ListLength(mLines); - if (!numLines) numLines = 1; - PRTime lines, deltaPerLine, delta; - LL_I2L(lines, numLines); - LL_SUB(delta, end, start); - LL_DIV(deltaPerLine, delta, lines); - - ListTag(stdout); - char buf[400]; - PR_snprintf(buf, sizeof(buf), - ": %lld elapsed (%lld per line) lines=%d drawn=%d skip=%d", - delta, deltaPerLine, - numLines, drawnLines, numLines - drawnLines); - printf("%s\n", buf); - } -#endif -} - - -NS_IMETHODIMP -nsBlockFrame::HandleEvent(nsIPresContext* aPresContext, - nsGUIEvent* aEvent, - nsEventStatus* aEventStatus) -{ - - nsresult result; - nsCOMPtr shell; - if (aEvent->message == NS_MOUSE_MOVE) { - aPresContext->GetShell(getter_AddRefs(shell)); - if (!shell) - return NS_OK; - nsCOMPtr frameSelection; - PRBool mouseDown = PR_FALSE; -//check to see if we need to ask the selection controller.. - if (mState & NS_FRAME_INDEPENDENT_SELECTION) - { - nsCOMPtr selCon; - result = GetSelectionController(aPresContext, getter_AddRefs(selCon)); - if (NS_FAILED(result) || !selCon) - return result?result:NS_ERROR_FAILURE; - frameSelection = do_QueryInterface(selCon); - } - else - shell->GetFrameSelection(getter_AddRefs(frameSelection)); - if (!frameSelection || NS_FAILED(frameSelection->GetMouseDownState(&mouseDown)) || !mouseDown) - return NS_OK;//do not handle - } - - if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN || aEvent->message == NS_MOUSE_MOVE || - aEvent->message == NS_MOUSE_LEFT_DOUBLECLICK ) { - - nsMouseEvent *me = (nsMouseEvent *)aEvent; - - nsIFrame *resultFrame = nsnull;//this will be passed the handle event when we - //can tell who to pass it to - nsCOMPtr it; - nsIFrame *mainframe = this; - nsCOMPtr tracker; - aPresContext->GetShell(getter_AddRefs(shell)); - if (!shell) - return NS_OK; - result = shell->QueryInterface(NS_GET_IID(nsIFocusTracker),getter_AddRefs(tracker)); - - result = mainframe->QueryInterface(NS_GET_IID(nsILineIterator),getter_AddRefs(it)); - nsIView* parentWithView; - nsPoint origin; - nsPeekOffsetStruct pos; - - while(NS_OK == result) - { //we are starting aloop to allow us to "drill down to the one we want" - mainframe->GetOffsetFromView(aPresContext, origin, &parentWithView); - - if (NS_FAILED(result)) - return NS_OK;//do not handle - PRInt32 countLines; - result = it->GetNumLines(&countLines); - if (NS_FAILED(result)) - return NS_OK;//do not handle - PRInt32 i; - PRInt32 lineFrameCount; - nsIFrame *firstFrame; - nsRect rect; - PRInt32 closestLine = 0; - PRInt32 closestDistance = 999999; //some HUGE number that will always fail first comparison - //incase we hit another block frame. - for (i = 0; i< countLines;i++) - { - PRUint32 flags; - result = it->GetLine(i, &firstFrame, &lineFrameCount,rect,&flags); - if (NS_FAILED(result)) - continue;//do not handle - rect+=origin; - rect.width = aEvent->point.x - rect.x+1;//EXTEND RECT TO REACH POINT - if (rect.Contains(aEvent->point.x, aEvent->point.y)) - { - closestLine = i; - break; - } - else - { - PRInt32 distance = PR_MIN(abs(rect.y - aEvent->point.y),abs((rect.y + rect.height) - aEvent->point.y)); - if (distance < closestDistance) - { - closestDistance = distance; - closestLine = i; - } - else if (distance > closestDistance) - break;//done - } - } - //we will now ask where to go. if we cant find what we want"aka another block frame" - //we drill down again - pos.mTracker = tracker; - pos.mDirection = eDirNext; - pos.mDesiredX = aEvent->point.x; - - result = nsFrame::GetNextPrevLineFromeBlockFrame(aPresContext, - &pos, - mainframe, - closestLine-1, - 0 - ); - - if (NS_SUCCEEDED(result) && pos.mResultFrame){ - if (result == NS_OK) - result = pos.mResultFrame->QueryInterface(NS_GET_IID(nsILineIterator),getter_AddRefs(it));//if this fails thats ok - resultFrame = pos.mResultFrame; - mainframe = resultFrame; - } - else - break;//time to go nothing was found - } - //end while loop. if nssucceeded resutl then keep going that means - //we have successfully hit another block frame and we should keep going. - - - if (resultFrame) - { - if (NS_COMFALSE == result) - { - nsCOMPtr selCon; - result = GetSelectionController(aPresContext, getter_AddRefs(selCon)); - //get the selection controller - if (NS_SUCCEEDED(result) && selCon) - { - PRInt16 displayresult; - selCon->GetDisplaySelection(&displayresult); - if (displayresult == nsISelectionController::SELECTION_OFF) - return NS_OK;//nothing to do we cannot affect selection from here - } - nsCOMPtr frameselection; - shell->GetFrameSelection(getter_AddRefs(frameselection)); - if (frameselection) - result = frameselection->HandleClick(pos.mResultContent, pos.mContentOffset, - pos.mContentOffsetEnd, me->isShift, PR_FALSE, pos.mPreferLeft); - } - else - result = resultFrame->HandleEvent(aPresContext, aEvent, aEventStatus);//else let the frame/container do what it needs - if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN && !IsMouseCaptured(aPresContext)) - CaptureMouse(aPresContext, PR_TRUE); - return result; - } - else - { - /*we have to add this because any frame that overrides nsFrame::HandleEvent for mouse down MUST capture the mouse events!! - if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN && !IsMouseCaptured(aPresContext)) - CaptureMouse(aPresContext, PR_TRUE);*/ - return NS_OK; //just stop it - } - } - return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); -} - - -NS_IMETHODIMP -nsBlockFrame::GetFrameForPoint(nsIPresContext* aPresContext, - const nsPoint& aPoint, - nsFramePaintLayer aWhichLayer, - nsIFrame** aFrame) -{ - nsresult rv; - - switch (aWhichLayer) { - case NS_FRAME_PAINT_LAYER_FOREGROUND: - rv = GetFrameForPointUsing(aPresContext, aPoint, nsnull, NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE, aFrame); - if (NS_OK == rv) { - return NS_OK; - } - if (nsnull != mBullet) { - rv = GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::bulletList, NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE, aFrame); - } - return rv; - break; - - case NS_FRAME_PAINT_LAYER_FLOATERS: - // we painted our floaters before our children, and thus - // we should check floaters within children first - rv = GetFrameForPointUsing(aPresContext, aPoint, nsnull, NS_FRAME_PAINT_LAYER_FLOATERS, PR_FALSE, aFrame); - if (NS_OK == rv) { - return NS_OK; - } - if (mFloaters.NotEmpty()) { - - rv = GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::floaterList, NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE, aFrame); - if (NS_OK == rv) { - return NS_OK; - } - - rv = GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::floaterList, NS_FRAME_PAINT_LAYER_FLOATERS, PR_FALSE, aFrame); - if (NS_OK == rv) { - return NS_OK; - } - - return GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::floaterList, NS_FRAME_PAINT_LAYER_BACKGROUND, PR_FALSE, aFrame); - - } else { - return NS_ERROR_FAILURE; - } - break; - - case NS_FRAME_PAINT_LAYER_BACKGROUND: - // we're a block, so PR_TRUE for consider self - return GetFrameForPointUsing(aPresContext, aPoint, nsnull, NS_FRAME_PAINT_LAYER_BACKGROUND, PR_TRUE, aFrame); - break; - } - // we shouldn't get here - NS_ASSERTION(PR_FALSE, "aWhichLayer was not understood"); - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsBlockFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) -{ - if (aChild) { - // See if the child is absolutely positioned - nsFrameState childState; - aChild->GetFrameState(&childState); - if (childState & NS_FRAME_OUT_OF_FLOW) { - const nsStylePosition* position; - aChild->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)position); - - if (position->IsAbsolutelyPositioned()) { - // Generate a reflow command to reflow our dirty absolutely - // positioned child frames. - // XXX Note that we don't currently try and coalesce the reflow commands, - // although we should. We can't use the NS_FRAME_HAS_DIRTY_CHILDREN - // flag, because that's used to indicate whether in-flow children are - // dirty... - nsIReflowCommand* reflowCmd; - nsresult rv = NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - reflowCmd->SetChildListName(nsLayoutAtoms::absoluteList); - aPresShell->AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - return rv; - } - } - - // Mark the line containing the child frame dirty. - PRBool isFloater; - nsLineBox* prevLine; - nsLineBox* line = FindLineFor(aChild, &prevLine, &isFloater); - - if (!isFloater) { - if (line) - MarkLineDirty(line, prevLine); - } - else { - line = mLines; - while (nsnull != line) { - line->MarkDirty(); - line = line->mNext; - } - } - } - - // Either generate a reflow command to reflow the dirty child or - // coalesce this reflow request with an existing reflow command - if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) { - // If this is the first dirty child, - // post a dirty children reflow command targeted at yourself - mState |= NS_FRAME_HAS_DIRTY_CHILDREN; - - nsFrame::CreateAndPostReflowCommand(aPresShell, this, - nsIReflowCommand::ReflowDirty, nsnull, nsnull, nsnull); - } - else { - if (!(mState & NS_FRAME_IS_DIRTY)) { - // Mark yourself as dirty - mState |= NS_FRAME_IS_DIRTY; - - // Cancel the dirty children reflow command you posted earlier - nsIReflowCommand::ReflowType type = nsIReflowCommand::ReflowDirty; - aPresShell->CancelReflowCommand(this, &type); - - // Pass up the reflow request to the parent frame. - mParent->ReflowDirtyChild(aPresShell, this); - } - } - - return NS_OK; -} - -////////////////////////////////////////////////////////////////////// -// Debugging - -#ifdef NS_DEBUG -static PRBool -InLineList(nsLineBox* aLines, nsIFrame* aFrame) -{ - while (nsnull != aLines) { - nsIFrame* frame = aLines->mFirstChild; - PRInt32 n = aLines->GetChildCount(); - while (--n >= 0) { - if (frame == aFrame) { - return PR_TRUE; - } - frame->GetNextSibling(&frame); - } - aLines = aLines->mNext; - } - return PR_FALSE; -} - -static PRBool -InSiblingList(nsLineBox* aLine, nsIFrame* aFrame) -{ - if (nsnull != aLine) { - nsIFrame* frame = aLine->mFirstChild; - while (nsnull != frame) { - if (frame == aFrame) { - return PR_TRUE; - } - frame->GetNextSibling(&frame); - } - } - return PR_FALSE; -} - -PRBool -nsBlockFrame::IsChild(nsIPresContext* aPresContext, nsIFrame* aFrame) -{ - nsIFrame* parent; - aFrame->GetParent(&parent); - if (parent != (nsIFrame*)this) { - return PR_FALSE; - } - if (InLineList(mLines, aFrame) && InSiblingList(mLines, aFrame)) { - return PR_TRUE; - } - nsLineBox* overflowLines = GetOverflowLines(aPresContext, PR_FALSE); - if (InLineList(overflowLines, aFrame) && InSiblingList(overflowLines, aFrame)) { - return PR_TRUE; - } - return PR_FALSE; -} - -NS_IMETHODIMP -nsBlockFrame::VerifyTree() const -{ - // XXX rewrite this - return NS_OK; -} - -NS_IMETHODIMP -nsBlockFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const -{ - if (!aHandler || !aResult) { - return NS_ERROR_NULL_POINTER; - } - - PRUint32 sum = sizeof(*this); - - // Add in size of each line object - nsLineBox* line = mLines; - while (line) { - PRUint32 lineBoxSize; - nsIAtom* atom = line->SizeOf(aHandler, &lineBoxSize); - aHandler->AddSize(atom, lineBoxSize); - line = line->mNext; - } - - *aResult = sum; - return NS_OK; -} -#endif - -//---------------------------------------------------------------------- - -NS_IMETHODIMP -nsBlockFrame::Init(nsIPresContext* aPresContext, - nsIContent* aContent, - nsIFrame* aParent, - nsIStyleContext* aContext, - nsIFrame* aPrevInFlow) -{ - if (aPrevInFlow) { - // Copy over the block/area frame type flags - nsBlockFrame* blockFrame = (nsBlockFrame*)aPrevInFlow; - - SetFlags(blockFrame->mState & NS_BLOCK_FLAGS_MASK); - } - - nsresult rv = nsBlockFrameSuper::Init(aPresContext, aContent, aParent, - aContext, aPrevInFlow); - return rv; -} - -nsIStyleContext* -nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext) -{ - nsIStyleContext* fls; - aPresContext->ProbePseudoStyleContextFor(mContent, - nsHTMLAtoms::firstLetterPseudo, - mStyleContext, PR_FALSE, &fls); - return fls; -} - -NS_IMETHODIMP -nsBlockFrame::SetInitialChildList(nsIPresContext* aPresContext, - nsIAtom* aListName, - nsIFrame* aChildList) -{ - nsresult rv = NS_OK; - - if (nsLayoutAtoms::absoluteList == aListName) { - mAbsoluteContainer.SetInitialChildList(this, aPresContext, aListName, aChildList); - } - else if (nsLayoutAtoms::floaterList == aListName) { - mFloaters.SetFrames(aChildList); - } - else { - - // Lookup up the two pseudo style contexts - if (nsnull == mPrevInFlow) { - nsIStyleContext* firstLetterStyle = GetFirstLetterStyle(aPresContext); - if (nsnull != firstLetterStyle) { - mState |= NS_BLOCK_HAS_FIRST_LETTER_STYLE; -#ifdef NOISY_FIRST_LETTER - ListTag(stdout); - printf(": first-letter style found\n"); -#endif - NS_RELEASE(firstLetterStyle); - } - } - - rv = AddFrames(aPresContext, aChildList, nsnull); - if (NS_FAILED(rv)) { - return rv; - } - - // Create list bullet if this is a list-item. Note that this is done - // here so that RenumberLists will work (it needs the bullets to - // store the bullet numbers). - const nsStyleDisplay* styleDisplay; - GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay); - if ((nsnull == mPrevInFlow) && - (NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) && - (nsnull == mBullet)) { - // Resolve style for the bullet frame - nsIStyleContext* kidSC; - aPresContext->ResolvePseudoStyleContextFor(mContent, - nsHTMLAtoms::mozListBulletPseudo, - mStyleContext, PR_FALSE, &kidSC); - - // Create bullet frame - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - mBullet = new (shell.get()) nsBulletFrame; - - if (nsnull == mBullet) { - NS_RELEASE(kidSC); - return NS_ERROR_OUT_OF_MEMORY; - } - mBullet->Init(aPresContext, mContent, this, kidSC, nsnull); - NS_RELEASE(kidSC); - - // If the list bullet frame should be positioned inside then add - // it to the flow now. - const nsStyleList* styleList; - GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList); - if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == - styleList->mListStylePosition) { - AddFrames(aPresContext, mBullet, nsnull); - mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; - } - else { - mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; - } - } - } - - return NS_OK; -} - -PRBool -nsBlockFrame::FrameStartsCounterScope(nsIFrame* aFrame) -{ - const nsStyleContent* styleContent; - aFrame->GetStyleData(eStyleStruct_Content, - (const nsStyleStruct*&) styleContent); - if (0 != styleContent->CounterResetCount()) { - // Winner - return PR_TRUE; - } - return PR_FALSE; -} - -void -nsBlockFrame::RenumberLists(nsIPresContext* aPresContext) -{ - if (!FrameStartsCounterScope(this)) { - // If this frame doesn't start a counter scope then we don't need - // to renumber child list items. - return; - } - - // Setup initial list ordinal value - // XXX Map html's start property to counter-reset style - PRInt32 ordinal = 1; - nsIHTMLContent* hc; - if (mContent && (NS_OK == mContent->QueryInterface(kIHTMLContentIID, (void**) &hc))) { - nsHTMLValue value; - if (NS_CONTENT_ATTR_HAS_VALUE == - hc->GetHTMLAttribute(nsHTMLAtoms::start, value)) { - if (eHTMLUnit_Integer == value.GetUnit()) { - ordinal = value.GetIntValue(); - if (ordinal <= 0) { - ordinal = 1; - } - } - } - NS_RELEASE(hc); - } - - // Get to first-in-flow - nsBlockFrame* block = (nsBlockFrame*) GetFirstInFlow(); - RenumberListsInBlock(aPresContext, block, &ordinal, 0); -} - -PRBool -nsBlockFrame::RenumberListsInBlock(nsIPresContext* aPresContext, - nsBlockFrame* aBlockFrame, - PRInt32* aOrdinal, - PRInt32 aDepth) -{ - PRBool renumberedABullet = PR_FALSE; - - while (nsnull != aBlockFrame) { - // Examine each line in the block - nsLineBox* line = aBlockFrame->mLines; - while (line) { - nsIFrame* kid = line->mFirstChild; - PRInt32 n = line->GetChildCount(); - while (--n >= 0) { - PRBool kidRenumberedABullet = RenumberListsFor(aPresContext, kid, aOrdinal, aDepth); - if (kidRenumberedABullet) { - line->MarkDirty(); - renumberedABullet = PR_TRUE; - } - kid->GetNextSibling(&kid); - } - line = line->mNext; - } - - // Advance to the next continuation - aBlockFrame->GetNextInFlow((nsIFrame**) &aBlockFrame); - } - - return renumberedABullet; -} - -// XXX temporary code: after ib work is done in frame construction -// code this can be removed. -PRBool -nsBlockFrame::RenumberListsIn(nsIPresContext* aPresContext, - nsIFrame* aContainerFrame, - PRInt32* aOrdinal, - PRInt32 aDepth) -{ - PRBool renumberedABullet = PR_FALSE; - - // For each flow-block... - while (nsnull != aContainerFrame) { - // For each frame in the flow-block... - nsIFrame* kid; - aContainerFrame->FirstChild(aPresContext, nsnull, &kid); - while (nsnull != kid) { - PRBool kidRenumberedABullet = RenumberListsFor(aPresContext, kid, aOrdinal, aDepth); - if (kidRenumberedABullet) { - renumberedABullet = PR_TRUE; - } - kid->GetNextSibling(&kid); - } - aContainerFrame->GetNextInFlow(&aContainerFrame); - } - return renumberedABullet; -} - -PRBool -nsBlockFrame::RenumberListsFor(nsIPresContext* aPresContext, - nsIFrame* aKid, - PRInt32* aOrdinal, - PRInt32 aDepth) -{ - NS_ASSERTION(aPresContext && aKid && aOrdinal, "null params are immoral!"); - - // add in a sanity check for absurdly deep frame trees. See bug 42138 - if (MAX_DEPTH_FOR_LIST_RENUMBERING < aDepth) - return PR_FALSE; - - PRBool kidRenumberedABullet = PR_FALSE; - nsIFrame* kid = aKid; - - // if the frame is a placeholder, then get the out of flow frame - nsCOMPtr frameType; - aKid->GetFrameType(getter_AddRefs(frameType)); - if (nsLayoutAtoms::placeholderFrame == frameType.get()) { - kid = NS_STATIC_CAST(nsPlaceholderFrame*, aKid)->GetOutOfFlowFrame(); - NS_ASSERTION(kid, "no out-of-flow frame"); - } - - // If the frame is a list-item and the frame implements our - // block frame API then get it's bullet and set the list item - // ordinal. - const nsStyleDisplay* display; - kid->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) { - // Make certain that the frame isa block-frame in case - // something foreign has crept in. - nsBlockFrame* listItem; - nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**)&listItem); - if (NS_SUCCEEDED(rv)) { - if (nsnull != listItem->mBullet) { - PRBool changed; - *aOrdinal = listItem->mBullet->SetListItemOrdinal(*aOrdinal, - &changed); - if (changed) { - kidRenumberedABullet = PR_TRUE; - } - } - - // XXX temporary? if the list-item has child list-items they - // should be numbered too; especially since the list-item is - // itself (ASSUMED!) not to be a counter-reseter. - PRBool meToo = RenumberListsInBlock(aPresContext, listItem, aOrdinal, aDepth + 1); - if (meToo) { - kidRenumberedABullet = PR_TRUE; - } - } - } - else if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) { - if (FrameStartsCounterScope(kid)) { - // Don't bother recursing into a block frame that is a new - // counter scope. Any list-items in there will be handled by - // it. - } - else { - // If the display=block element ISA block-frame then go - // ahead and recurse into it as it might have child - // list-items. - nsBlockFrame* kidBlock; - nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**) &kidBlock); - if (NS_SUCCEEDED(rv)) { - kidRenumberedABullet = RenumberListsInBlock(aPresContext, kidBlock, aOrdinal, aDepth + 1); - } - } - } else if (NS_STYLE_DISPLAY_INLINE == display->mDisplay) { - // XXX temporary code: after ib work is done in frame construction - // code this can be removed. - - // If the display=inline element ISA nsInlineFrame then go - // ahead and recurse into it as it might have child - // list-items. - nsInlineFrame* kidInline; - nsresult rv = kid->QueryInterface(nsInlineFrame::kInlineFrameCID, - (void**) &kidInline); - if (NS_SUCCEEDED(rv)) { - kidRenumberedABullet = RenumberListsIn(aPresContext, kid, aOrdinal, aDepth + 1); - } - } - return kidRenumberedABullet; -} - -void -nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, - nsHTMLReflowMetrics& aMetrics) -{ - // Reflow the bullet now - nsSize availSize; - availSize.width = NS_UNCONSTRAINEDSIZE; - availSize.height = NS_UNCONSTRAINEDSIZE; - nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState, - mBullet, availSize); - nsReflowStatus status; - mBullet->WillReflow(aState.mPresContext); - mBullet->Reflow(aState.mPresContext, aMetrics, reflowState, status); - -#ifdef IBMBIDI - const nsStyleDisplay* display; - GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); -#endif // IBMBIDI - // Place the bullet now; use its right margin to distance it - // from the rest of the frames in the line - nscoord x = -#ifdef IBMBIDI - // For direction RTL: set x to the right margin for now. - // This value will be used to indent the bullet from the right most - // egde of the previous frame in nsLineLayout::HorizontalAlignFrames. - (NS_STYLE_DIRECTION_RTL == display->mDirection) - ? reflowState.mComputedMargin.right : -#endif // IBMBIDI - - reflowState.mComputedMargin.right - aMetrics.width; - - // Approximate the bullets position; vertical alignment will provide - // the final vertical location. - const nsMargin& bp = aState.BorderPadding(); - nscoord y = bp.top; - mBullet->SetRect(aState.mPresContext, nsRect(x, y, aMetrics.width, aMetrics.height)); - mBullet->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED); -} - -//XXX get rid of this -- its slow -void -nsBlockFrame::BuildFloaterList() -{ - nsIFrame* head = nsnull; - nsIFrame* current = nsnull; - nsLineBox* line = mLines; - while (nsnull != line) { - if (line->HasFloaters()) { - nsFloaterCache* fc = line->GetFirstFloater(); - while (fc) { - nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame(); - if (nsnull == head) { - current = head = floater; - } - else { - current->SetNextSibling(floater); - current = floater; - } - fc = fc->Next(); - } - } - line = line->mNext; - } - - // Terminate end of floater list just in case a floater was removed - if (nsnull != current) { - current->SetNextSibling(nsnull); - } - mFloaters.SetFrames(head); -} - -// XXX keep the text-run data in the first-in-flow of the block - -#ifdef DEBUG -void -nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) -{ - if (!gVerifyLines) { - return; - } - nsLineBox* line = mLines; - if (!line) { - return; - } - - // Add up the counts on each line. Also validate that IsFirstLine is - // set properly. - PRInt32 count = 0; - PRBool seenBlock = PR_FALSE; - while (nsnull != line) { - if (aFinalCheckOK) { - NS_ABORT_IF_FALSE(line->GetChildCount(), "empty line"); - if (line->IsBlock()) { - seenBlock = PR_TRUE; - } - if (line->IsBlock()) { - NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); - } - } - count += line->GetChildCount(); - line = line->mNext; - } - - // Then count the frames - PRInt32 frameCount = 0; - nsIFrame* frame = mLines->mFirstChild; - while (nsnull != frame) { - frameCount++; - frame->GetNextSibling(&frame); - } - NS_ASSERTION(count == frameCount, "bad line list"); - - // Next: test that each line has right number of frames on it - line = mLines; - nsLineBox* prevLine = nsnull; - while (nsnull != line) { - count = line->GetChildCount(); - frame = line->mFirstChild; - while (--count >= 0) { - frame->GetNextSibling(&frame); - } - prevLine = line; - line = line->mNext; - if ((nsnull != line) && (0 != line->GetChildCount())) { - NS_ASSERTION(frame == line->mFirstChild, "bad line list"); - } - } -} - -// Its possible that a frame can have some frames on an overflow -// list. But its never possible for multiple frames to have overflow -// lists. Check that this fact is actually true. -void -nsBlockFrame::VerifyOverflowSituation(nsIPresContext* aPresContext) -{ - nsBlockFrame* flow = (nsBlockFrame*) GetFirstInFlow(); - while (nsnull != flow) { - nsLineBox* overflowLines = GetOverflowLines(aPresContext, PR_FALSE); - if (nsnull != overflowLines) { - NS_ASSERTION(nsnull != overflowLines->mFirstChild, - "bad overflow list"); - } - flow = (nsBlockFrame*) flow->mNextInFlow; - } -} - -PRInt32 -nsBlockFrame::GetDepth() const -{ - PRInt32 depth = 0; - nsIFrame* parent = mParent; - while (nsnull != parent) { - parent->GetParent(&parent); - depth++; - } - return depth; -} -#endif diff --git a/layout/html/base/src/nsBlockReflowState.cpp b/layout/html/base/src/nsBlockReflowState.cpp index bbba65921ec..7791d909025 100644 --- a/layout/html/base/src/nsBlockReflowState.cpp +++ b/layout/html/base/src/nsBlockReflowState.cpp @@ -22,571 +22,6 @@ * Robert O'Callahan * L. David Baron */ -#include "nsCOMPtr.h" -#include "nsBlockFrame.h" -#include "nsBlockReflowContext.h" -#include "nsBlockBandData.h" -#include "nsBulletFrame.h" -#include "nsLineBox.h" -#include "nsInlineFrame.h" -#include "nsLineLayout.h" -#include "nsPlaceholderFrame.h" -#include "nsStyleConsts.h" -#include "nsHTMLIIDs.h" -#include "nsCSSRendering.h" -#include "nsIFrameManager.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsIReflowCommand.h" -#include "nsISpaceManager.h" -#include "nsIStyleContext.h" -#include "nsIView.h" -#include "nsIFontMetrics.h" -#include "nsHTMLParts.h" -#include "nsHTMLAtoms.h" -#include "nsHTMLValue.h" -#include "nsIDOMEvent.h" -#include "nsIHTMLContent.h" -#include "prprf.h" -#include "nsLayoutAtoms.h" -#include "nsITextContent.h" -#include "nsStyleChangeList.h" -#include "nsISizeOfHandler.h" -#include "nsIFocusTracker.h" -#include "nsIFrameSelection.h" -#include "nsSpaceManager.h" -#include "prenv.h" -#include "plstr.h" - -#ifdef IBMBIDI -#include "nsBidiPresUtils.h" -#endif // IBMBIDI - -#include "nsIDOMHTMLBodyElement.h" -#include "nsIDOMHTMLHtmlElement.h" - -#ifdef DEBUG - -static PRBool gLamePaintMetrics; -static PRBool gLameReflowMetrics; -static PRBool gNoisy; -static PRBool gNoisyDamageRepair; -static PRBool gNoisyMaxElementSize; -static PRBool gNoisyReflow; -static PRBool gReallyNoisyReflow; -static PRBool gNoisySpaceManager; -static PRBool gVerifyLines; -static PRBool gDisableResizeOpt; - -struct BlockDebugFlags { - const char* name; - PRBool* on; -}; - -static BlockDebugFlags gFlags[] = { - { "reflow", &gNoisyReflow }, - { "really-noisy-reflow", &gReallyNoisyReflow }, - { "max-element-size", &gNoisyMaxElementSize }, - { "space-manager", &gNoisySpaceManager }, - { "verify-lines", &gVerifyLines }, - { "damage-repair", &gNoisyDamageRepair }, - { "lame-paint-metrics", &gLamePaintMetrics }, - { "lame-reflow-metrics", &gLameReflowMetrics }, - { "disable-resize-opt", &gDisableResizeOpt }, -}; -#define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0])) - -static void -ShowDebugFlags() -{ - printf("Here are the available GECKO_BLOCK_DEBUG_FLAGS:\n"); - BlockDebugFlags* bdf = gFlags; - BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS; - for (; bdf < end; bdf++) { - printf(" %s\n", bdf->name); - } - printf("Note: GECKO_BLOCK_DEBUG_FLAGS is a comma seperated list of flag\n"); - printf("names (no whitespace)\n"); -} - -static void -InitDebugFlags() -{ - static PRBool firstTime = PR_TRUE; - if (firstTime) { - firstTime = PR_FALSE; - char* flags = PR_GetEnv("GECKO_BLOCK_DEBUG_FLAGS"); - if (flags) { - PRBool error = PR_FALSE; - for (;;) { - char* cm = PL_strchr(flags, ','); - if (cm) *cm = '\0'; - - PRBool found = PR_FALSE; - BlockDebugFlags* bdf = gFlags; - BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS; - for (; bdf < end; bdf++) { - if (PL_strcasecmp(bdf->name, flags) == 0) { - *(bdf->on) = PR_TRUE; - printf("nsBlockFrame: setting %s debug flag on\n", bdf->name); - gNoisy = PR_TRUE; - found = PR_TRUE; - break; - } - } - if (!found) { - error = PR_TRUE; - } - - if (!cm) break; - *cm = ','; - flags = cm + 1; - } - if (error) { - ShowDebugFlags(); - } - } - } -} - -#undef NOISY_FIRST_LINE // enables debug output for first-line specific layout -#undef REALLY_NOISY_FIRST_LINE // enables extra debug output for first-line specific layout -#undef NOISY_FIRST_LETTER // enables debug output for first-letter specific layout -#undef NOISY_MAX_ELEMENT_SIZE // enables debug output for max element size computation -#undef NOISY_MAXIMUM_WIDTH // enables debug output for max width computation -#undef NOISY_KIDXMOST // enables debug output for aState.mKidXMost computation -#undef NOISY_FLOATER // enables debug output for floater reflow (the in/out metrics for the floated block) -#undef NOISY_FLOATER_CLEARING -#undef NOISY_FINAL_SIZE // enables debug output for desired width/height computation, once all children have been reflowed -#undef NOISY_REMOVE_FRAME -#undef NOISY_COMBINED_AREA // enables debug output for combined area computation -#undef NOISY_VERTICAL_MARGINS -#undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested -#undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete" -#undef NOISY_SPACEMANAGER // enables debug output for space manager use, useful for analysing reflow of floaters and positioned elements -#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate -#undef REALLY_NOISY_REFLOW // some extra debug info - -#endif - -#define FIX_BUG_38157 -#define FIX_BUG_37657 - -// add in a sanity check for absurdly deep frame trees. See bug 42138 -// can't just use IsFrameTreeTooDeep() because that method has side effects we don't want -#define MAX_DEPTH_FOR_LIST_RENUMBERING 200 // 200 open displayable tags is pretty unrealistic - -//---------------------------------------------------------------------- - -// Debugging support code - -#ifdef DEBUG -static PRInt32 gNoiseIndent; -static const char* kReflowCommandType[] = { - "ContentChanged", - "StyleChanged", - "PullupReflow", - "PushReflow", - "CheckPullupReflow", - "ReflowDirty", - "UserDefined", -}; -#endif - -#ifdef REALLY_NOISY_FIRST_LINE -static void -DumpStyleGeneaology(nsIFrame* aFrame, const char* gap) -{ - fputs(gap, stdout); - nsFrame::ListTag(stdout, aFrame); - printf(": "); - nsIStyleContext* sc; - aFrame->GetStyleContext(&sc); - while (nsnull != sc) { - nsIStyleContext* psc; - printf("%p ", sc); - psc = sc->GetParent(); - NS_RELEASE(sc); - sc = psc; - } - printf("\n"); -} -#endif - -#ifdef REFLOW_STATUS_COVERAGE -static void -RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus) -{ - static PRUint32 record[2]; - - // 0: child-is-block - // 1: child-is-inline - PRIntn index = 0; - if (!aChildIsBlock) index |= 1; - - // Compute new status - PRUint32 newS = record[index]; - if (NS_INLINE_IS_BREAK(aFrameReflowStatus)) { - if (NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) { - newS |= 1; - } - else if (NS_FRAME_IS_NOT_COMPLETE(aFrameReflowStatus)) { - newS |= 2; - } - else { - newS |= 4; - } - } - else if (NS_FRAME_IS_NOT_COMPLETE(aFrameReflowStatus)) { - newS |= 8; - } - else { - newS |= 16; - } - - // Log updates to the status that yield different values - if (record[index] != newS) { - record[index] = newS; - printf("record(%d): %02x %02x\n", index, record[0], record[1]); - } -} -#endif - -//---------------------------------------------------------------------- - -inline void CombineRects(const nsRect& r1, nsRect& r2) -{ - nscoord xa = r2.x; - nscoord ya = r2.y; - nscoord xb = xa + r2.width; - nscoord yb = ya + r2.height; - nscoord x = r1.x; - nscoord y = r1.y; - nscoord xmost = x + r1.width; - nscoord ymost = y + r1.height; - if (x < xa) { - xa = x; - } - if (xmost > xb) { - xb = xmost; - } - if (y < ya) { - ya = y; - } - if (ymost > yb) { - yb = ymost; - } - r2.x = xa; - r2.y = ya; - r2.width = xb - xa; - r2.height = yb - ya; -} - -//---------------------------------------------------------------------- - -class nsBlockReflowState { -public: - nsBlockReflowState(const nsHTMLReflowState& aReflowState, - nsIPresContext* aPresContext, - nsBlockFrame* aFrame, - const nsHTMLReflowMetrics& aMetrics, - PRBool aBlockMarginRoot); - - ~nsBlockReflowState(); - - /** - * Update our state when aLine is skipped over during incremental - * reflow. - */ - void RecoverStateFrom(nsLineBox* aLine, PRBool aPrevLineWasClean); - - /** - * 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) { -#ifdef DEBUG - // Verify that the caller setup the coordinate system properly - nscoord wx, wy; - mSpaceManager->GetTranslation(wx, wy); - NS_ASSERTION((wx == mSpaceManagerX) && (wy == mSpaceManagerY), - "bad coord system"); -#endif - - mBand.GetAvailableSpace(aY - BorderPadding().top, mAvailSpaceRect); - -#ifdef DEBUG - if (gNoisyReflow) { - nsFrame::IndentBy(stdout, gNoiseIndent); - printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n", - mAvailSpaceRect.x, mAvailSpaceRect.y, - mAvailSpaceRect.width, mAvailSpaceRect.height, - mBand.GetTrapezoidCount()); - } -#endif - } - - void InitFloater(nsLineLayout& aLineLayout, - nsPlaceholderFrame* aPlaceholderFrame); - - void AddFloater(nsLineLayout& aLineLayout, - nsPlaceholderFrame* aPlaceholderFrame, - PRBool aInitialReflow); - - PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats); - - void PlaceFloater(nsFloaterCache* aFloaterCache, - PRBool* aIsLeftFloater); - - void PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aFloaters); - - void ClearFloaters(nscoord aY, PRUint8 aBreakType); - - PRBool ClearPastFloaters(PRUint8 aBreakType); - - PRBool IsLeftMostChild(nsIPresContext* aPresContext, nsIFrame* aFrame); - - PRBool IsAdjacentWithTop() const { - return mY == mReflowState.mComputedBorderPadding.top; - } - - const nsMargin& BorderPadding() const { - return mReflowState.mComputedBorderPadding; - } - - const nsMargin& Margin() const { - return mReflowState.mComputedMargin; - } - - void UpdateMaxElementSize(const nsSize& aMaxElementSize) { -#ifdef NOISY_MAX_ELEMENT_SIZE - nsSize oldSize = mMaxElementSize; -#endif - if (aMaxElementSize.width > mMaxElementSize.width) { - mMaxElementSize.width = aMaxElementSize.width; - } - if (aMaxElementSize.height > mMaxElementSize.height) { - mMaxElementSize.height = aMaxElementSize.height; - } -#ifdef NOISY_MAX_ELEMENT_SIZE - if ((mMaxElementSize.width != oldSize.width) || - (mMaxElementSize.height != oldSize.height)) { - nsFrame::IndentBy(stdout, mBlock->GetDepth()); - if (NS_UNCONSTRAINEDSIZE == mReflowState.availableWidth) { - printf("PASS1 "); - } - nsFrame::ListTag(stdout, mBlock); - printf(": old max-element-size=%d,%d new=%d,%d\n", - oldSize.width, oldSize.height, - mMaxElementSize.width, mMaxElementSize.height); - } -#endif - } - - void UpdateMaximumWidth(nscoord aMaximumWidth) { - if (aMaximumWidth > mMaximumWidth) { -#ifdef NOISY_MAXIMUM_WIDTH - printf("nsBlockReflowState::UpdateMaximumWidth block %p caching max width %d\n", mBlock, aMaximumWidth); -#endif - mMaximumWidth = aMaximumWidth; - } - } - - void RecoverVerticalMargins(nsLineBox* aLine, - PRBool aApplyTopMargin, - nscoord* aTopMarginResult, - nscoord* aBottomMarginResult); - - void ComputeBlockAvailSpace(nsIFrame* aFrame, - nsSplittableType aSplitType, - const nsStyleDisplay* aDisplay, - nsRect& aResult); - - void RecoverStateFrom(nsLineBox* aLine, - PRBool aApplyTopMargin, - nsRect* aDamageRect); - - void AdvanceToNextLine() { - mLineNumber++; - } - - PRBool IsImpactedByFloater() { -#ifdef REALLY_NOISY_REFLOW - printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n", - this, mBand.GetFloaterCount()); -#endif - return mBand.GetFloaterCount(); - } - - nsLineBox* NewLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock); - - void FreeLineBox(nsLineBox* aLine); - - void StoreMaxElementSize(nsIFrame* aFloater, const nsSize& aSize) { - mBand.StoreMaxElementSize(mPresContext, aFloater, aSize); - } - - //---------------------------------------- - - // This state is the "global" state computed once for the reflow of - // the block. - - // The block frame that is using this object - nsBlockFrame* mBlock; - - nsIPresContext* mPresContext; - - const nsHTMLReflowState& mReflowState; - - nsISpaceManager* mSpaceManager; - - // The coordinates within the spacemanager where the block is being - // placed after 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 floaters. - 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 - nsLineBox* mCurrentLine; - - // The previous line just reflowed - nsLineBox* mPrevLine; - - // 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 floaters placed so far - nsRect mFloaterCombinedArea; - - // For unconstained-width reflow, we keep the right floaters - // combined area stored seperately. - PRBool mHaveRightFloaters; - nsRect mRightFloaterCombinedArea; - - nsFloaterCacheFreeList mFloaterCacheFreeList; - - // Previous child. This is used when pulling up a frame to update - // the sibling list. - nsIFrame* mPrevChild; - - // The next immediate child frame that is the target of an - // incremental reflow command. Once that child has been reflowed we - // null this slot out. - nsIFrame* mNextRCFrame; - - // The previous child frames collapsed bottom margin value. - nscoord 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 floaters that are "current-line" floaters. These are - // added to the line after the line has been reflowed, to keep the - // list fiddling from being N^2. - nsFloaterCacheFreeList mCurrentLineFloaters; - - // The list of floaters which are "below current-line" - // floaters. These are reflowed/placed after the line is reflowed - // and placed. Again, this is done to keep the list fiddling from - // being N^2. - nsFloaterCacheFreeList mBelowCurrentLineFloaters; - - nsSize mMaxElementSize; - 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_ISINLINEINCRREFLOW 0x00000010 -#define BRS_NOWRAP 0x00000020 -#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing? -#define BRS_ISBOTTOMMARGINROOT 0x00000080 -#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin -#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200 -#define BRS_COMPUTEMAXWIDTH 0x00000400 -#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH - - PRInt16 mFlags; - - 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; - } -}; - -// XXX This is vile. Make it go away -void -nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame) -{ - mBlockRS->InitFloater(*this, aFrame); -} -void -nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) -{ - mBlockRS->AddFloater(*this, aFrame, PR_FALSE); -} //---------------------------------------------------------------------- @@ -6287,1170 +5722,3 @@ nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType) } #endif } - -////////////////////////////////////////////////////////////////////// -// Painting, event handling - -PRIntn -nsBlockFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_TOP; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_BOTTOM; - } - return skip; -} - -#ifdef DEBUG -static void ComputeCombinedArea(nsLineBox* aLine, - nscoord aWidth, nscoord aHeight, - nsRect& aResult) -{ - nscoord xa = 0, ya = 0, xb = aWidth, yb = aHeight; - while (nsnull != aLine) { - // Compute min and max x/y values for the reflowed frame's - // combined areas - nsRect lineCombinedArea; - aLine->GetCombinedArea(&lineCombinedArea); - nscoord x = lineCombinedArea.x; - nscoord y = lineCombinedArea.y; - nscoord xmost = x + lineCombinedArea.width; - nscoord ymost = y + lineCombinedArea.height; - if (x < xa) { - xa = x; - } - if (xmost > xb) { - xb = xmost; - } - if (y < ya) { - ya = y; - } - if (ymost > yb) { - yb = ymost; - } - aLine = aLine->mNext; - } - - aResult.x = xa; - aResult.y = ya; - aResult.width = xb - xa; - aResult.height = yb - ya; -} -#endif - -NS_IMETHODIMP -nsBlockFrame::IsVisibleForPainting(nsIPresContext * aPresContext, - nsIRenderingContext& aRenderingContext, - PRBool aCheckVis, - PRBool* aIsVisible) -{ - // first check to see if we are visible - if (aCheckVis) { - const nsStyleDisplay* disp = (const nsStyleDisplay*)((nsIStyleContext*)mStyleContext)->GetStyleData(eStyleStruct_Display); - if (!disp->IsVisible()) { - *aIsVisible = PR_FALSE; - return NS_OK; - } - } - - // Start by assuming we are visible and need to be painted - *aIsVisible = PR_TRUE; - - // NOTE: GetSelectionforVisCheck checks the pagination to make sure we are printing - // In otherwords, the selection will ALWAYS be null if we are not printing, meaning - // the visibility will be TRUE in that case - nsCOMPtr selection; - nsresult rv = GetSelectionForVisCheck(aPresContext, getter_AddRefs(selection)); - if (NS_SUCCEEDED(rv) && selection) { - nsCOMPtr node(do_QueryInterface(mContent)); - - nsCOMPtr html(do_QueryInterface(mContent)); - nsCOMPtr body(do_QueryInterface(mContent)); - - if (!html && !body) { - rv = selection->ContainsNode(node, PR_TRUE, aIsVisible); - } - } - - return rv; -} - -NS_IMETHODIMP -nsBlockFrame::Paint(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nsFramePaintLayer aWhichLayer) -{ - if (NS_FRAME_IS_UNFLOWABLE & mState) { - return NS_OK; - } - -#ifdef DEBUG - if (gNoisyDamageRepair) { - if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { - PRInt32 depth = GetDepth(); - nsRect ca; - ComputeCombinedArea(mLines, mRect.width, mRect.height, ca); - nsFrame::IndentBy(stdout, depth); - ListTag(stdout); - printf(": bounds=%d,%d,%d,%d dirty=%d,%d,%d,%d ca=%d,%d,%d,%d\n", - mRect.x, mRect.y, mRect.width, mRect.height, - aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height, - ca.x, ca.y, ca.width, ca.height); - } - } -#endif - - PRBool isVisible; - if (NS_FAILED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible))) { - return NS_ERROR_FAILURE; - } - - // Only paint the border and background if we're visible - if (isVisible && (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) && - (0 != mRect.width) && (0 != mRect.height)) { - PRIntn skipSides = GetSkipSides(); - const nsStyleColor* color = (const nsStyleColor*) - mStyleContext->GetStyleData(eStyleStruct_Color); - const nsStyleBorder* border = (const nsStyleBorder*) - mStyleContext->GetStyleData(eStyleStruct_Border); - const nsStyleOutline* outline = (const nsStyleOutline*) - mStyleContext->GetStyleData(eStyleStruct_Outline); - - // Paint background, border and outline - nsRect rect(0, 0, mRect.width, mRect.height); - nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *color, *border, 0, 0); - nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *border, mStyleContext, - skipSides); - nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *border, *outline, mStyleContext, 0); - } - - PRBool paintingSuppressed = PR_FALSE; - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - shell->IsPaintingSuppressed(&paintingSuppressed); - if (paintingSuppressed) - return NS_OK; - - const nsStyleDisplay* disp = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - - // If overflow is hidden then set the clip rect so that children don't - // leak out of us. Note that because overflow'-clip' only applies to - // the content area we do this after painting the border and background - if (NS_STYLE_OVERFLOW_HIDDEN == disp->mOverflow) { - aRenderingContext.PushState(); - SetOverflowClipRect(aRenderingContext); - } - - // Child elements have the opportunity to override the visibility - // property and display even if the parent is hidden - if (NS_FRAME_PAINT_LAYER_FLOATERS == aWhichLayer) { - PaintFloaters(aPresContext, aRenderingContext, aDirtyRect); - } - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); - - if (NS_STYLE_OVERFLOW_HIDDEN == disp->mOverflow) { - PRBool clipState; - aRenderingContext.PopState(clipState); - } - -#if 0 - if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) { - // Render the bands in the spacemanager - nsISpaceManager* sm = mSpaceManager; - - if (nsnull != sm) { - nsBlockBandData band; - band.Init(sm, nsSize(mRect.width, mRect.height)); - nscoord y = 0; - while (y < mRect.height) { - nsRect availArea; - band.GetAvailableSpace(y, availArea); - - // Render a box and a diagonal line through the band - aRenderingContext.SetColor(NS_RGB(0,255,0)); - aRenderingContext.DrawRect(0, availArea.y, - mRect.width, availArea.height); - aRenderingContext.DrawLine(0, availArea.y, - mRect.width, availArea.YMost()); - - // Render boxes and opposite diagonal lines around the - // unavailable parts of the band. - PRInt32 i; - for (i = 0; i < band.GetTrapezoidCount(); i++) { - const nsBandTrapezoid* trapezoid = band.GetTrapezoid(i); - if (nsBandTrapezoid::Available != trapezoid->mState) { - nsRect r; - trapezoid->GetRect(r); - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) { - aRenderingContext.SetColor(NS_RGB(0,255,128)); - } - else { - aRenderingContext.SetColor(NS_RGB(128,255,0)); - } - aRenderingContext.DrawRect(r); - aRenderingContext.DrawLine(r.x, r.YMost(), r.XMost(), r.y); - } - } - y = availArea.YMost(); - } - } - } -#endif - - return NS_OK; -} - -void -nsBlockFrame::PaintFloaters(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect) -{ - for (nsLineBox* line = mLines; nsnull != line; line = line->mNext) { - if (!line->HasFloaters()) { - continue; - } - nsFloaterCache* fc = line->GetFirstFloater(); - while (fc) { - nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame(); - PaintChild(aPresContext, aRenderingContext, aDirtyRect, - floater, NS_FRAME_PAINT_LAYER_BACKGROUND); - PaintChild(aPresContext, aRenderingContext, aDirtyRect, - floater, NS_FRAME_PAINT_LAYER_FLOATERS); - PaintChild(aPresContext, aRenderingContext, aDirtyRect, - floater, NS_FRAME_PAINT_LAYER_FOREGROUND); - fc = fc->Next(); - } - } -} - -void -nsBlockFrame::PaintChildren(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nsFramePaintLayer aWhichLayer) -{ -#ifdef DEBUG - PRInt32 depth = 0; - if (gNoisyDamageRepair) { - if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { - depth = GetDepth(); - } - } - PRTime start = LL_ZERO; // Initialize these variables to silence the compiler. - PRInt32 drawnLines = 0; // They will only be used if set (gLamePaintMetrics). - if (gLamePaintMetrics) { - start = PR_Now(); - drawnLines = 0; - } -#endif - - for (nsLineBox* line = mLines; nsnull != line; line = line->mNext) { - // If the line's combined area (which includes child frames that - // stick outside of the line's bounding box or our bounding box) - // intersects the dirty rect then paint the line. - if (line->CombinedAreaIntersects(aDirtyRect)) { -#ifdef DEBUG - if (gNoisyDamageRepair && - (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) { - nsRect lineCombinedArea; - line->GetCombinedArea(&lineCombinedArea); - nsFrame::IndentBy(stdout, depth+1); - printf("draw line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n", - line, line->mBounds.x, line->mBounds.y, - line->mBounds.width, line->mBounds.height, - lineCombinedArea.x, lineCombinedArea.y, - lineCombinedArea.width, lineCombinedArea.height); - } - if (gLamePaintMetrics) { - drawnLines++; - } -#endif - nsIFrame* kid = line->mFirstChild; - PRInt32 n = line->GetChildCount(); - while (--n >= 0) { - PaintChild(aPresContext, aRenderingContext, aDirtyRect, kid, - aWhichLayer); - kid->GetNextSibling(&kid); - } - } -#ifdef DEBUG - else { - if (gNoisyDamageRepair && - (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) { - nsRect lineCombinedArea; - line->GetCombinedArea(&lineCombinedArea); - nsFrame::IndentBy(stdout, depth+1); - printf("skip line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n", - line, line->mBounds.x, line->mBounds.y, - line->mBounds.width, line->mBounds.height, - lineCombinedArea.x, lineCombinedArea.y, - lineCombinedArea.width, lineCombinedArea.height); - } - } -#endif - } - - if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { - if ((nsnull != mBullet) && HaveOutsideBullet()) { - // Paint outside bullets manually - PaintChild(aPresContext, aRenderingContext, aDirtyRect, mBullet, - aWhichLayer); - } - } - -#ifdef DEBUG - if (gLamePaintMetrics) { - PRTime end = PR_Now(); - - PRInt32 numLines = nsLineBox::ListLength(mLines); - if (!numLines) numLines = 1; - PRTime lines, deltaPerLine, delta; - LL_I2L(lines, numLines); - LL_SUB(delta, end, start); - LL_DIV(deltaPerLine, delta, lines); - - ListTag(stdout); - char buf[400]; - PR_snprintf(buf, sizeof(buf), - ": %lld elapsed (%lld per line) lines=%d drawn=%d skip=%d", - delta, deltaPerLine, - numLines, drawnLines, numLines - drawnLines); - printf("%s\n", buf); - } -#endif -} - - -NS_IMETHODIMP -nsBlockFrame::HandleEvent(nsIPresContext* aPresContext, - nsGUIEvent* aEvent, - nsEventStatus* aEventStatus) -{ - - nsresult result; - nsCOMPtr shell; - if (aEvent->message == NS_MOUSE_MOVE) { - aPresContext->GetShell(getter_AddRefs(shell)); - if (!shell) - return NS_OK; - nsCOMPtr frameSelection; - PRBool mouseDown = PR_FALSE; -//check to see if we need to ask the selection controller.. - if (mState & NS_FRAME_INDEPENDENT_SELECTION) - { - nsCOMPtr selCon; - result = GetSelectionController(aPresContext, getter_AddRefs(selCon)); - if (NS_FAILED(result) || !selCon) - return result?result:NS_ERROR_FAILURE; - frameSelection = do_QueryInterface(selCon); - } - else - shell->GetFrameSelection(getter_AddRefs(frameSelection)); - if (!frameSelection || NS_FAILED(frameSelection->GetMouseDownState(&mouseDown)) || !mouseDown) - return NS_OK;//do not handle - } - - if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN || aEvent->message == NS_MOUSE_MOVE || - aEvent->message == NS_MOUSE_LEFT_DOUBLECLICK ) { - - nsMouseEvent *me = (nsMouseEvent *)aEvent; - - nsIFrame *resultFrame = nsnull;//this will be passed the handle event when we - //can tell who to pass it to - nsCOMPtr it; - nsIFrame *mainframe = this; - nsCOMPtr tracker; - aPresContext->GetShell(getter_AddRefs(shell)); - if (!shell) - return NS_OK; - result = shell->QueryInterface(NS_GET_IID(nsIFocusTracker),getter_AddRefs(tracker)); - - result = mainframe->QueryInterface(NS_GET_IID(nsILineIterator),getter_AddRefs(it)); - nsIView* parentWithView; - nsPoint origin; - nsPeekOffsetStruct pos; - - while(NS_OK == result) - { //we are starting aloop to allow us to "drill down to the one we want" - mainframe->GetOffsetFromView(aPresContext, origin, &parentWithView); - - if (NS_FAILED(result)) - return NS_OK;//do not handle - PRInt32 countLines; - result = it->GetNumLines(&countLines); - if (NS_FAILED(result)) - return NS_OK;//do not handle - PRInt32 i; - PRInt32 lineFrameCount; - nsIFrame *firstFrame; - nsRect rect; - PRInt32 closestLine = 0; - PRInt32 closestDistance = 999999; //some HUGE number that will always fail first comparison - //incase we hit another block frame. - for (i = 0; i< countLines;i++) - { - PRUint32 flags; - result = it->GetLine(i, &firstFrame, &lineFrameCount,rect,&flags); - if (NS_FAILED(result)) - continue;//do not handle - rect+=origin; - rect.width = aEvent->point.x - rect.x+1;//EXTEND RECT TO REACH POINT - if (rect.Contains(aEvent->point.x, aEvent->point.y)) - { - closestLine = i; - break; - } - else - { - PRInt32 distance = PR_MIN(abs(rect.y - aEvent->point.y),abs((rect.y + rect.height) - aEvent->point.y)); - if (distance < closestDistance) - { - closestDistance = distance; - closestLine = i; - } - else if (distance > closestDistance) - break;//done - } - } - //we will now ask where to go. if we cant find what we want"aka another block frame" - //we drill down again - pos.mTracker = tracker; - pos.mDirection = eDirNext; - pos.mDesiredX = aEvent->point.x; - - result = nsFrame::GetNextPrevLineFromeBlockFrame(aPresContext, - &pos, - mainframe, - closestLine-1, - 0 - ); - - if (NS_SUCCEEDED(result) && pos.mResultFrame){ - if (result == NS_OK) - result = pos.mResultFrame->QueryInterface(NS_GET_IID(nsILineIterator),getter_AddRefs(it));//if this fails thats ok - resultFrame = pos.mResultFrame; - mainframe = resultFrame; - } - else - break;//time to go nothing was found - } - //end while loop. if nssucceeded resutl then keep going that means - //we have successfully hit another block frame and we should keep going. - - - if (resultFrame) - { - if (NS_COMFALSE == result) - { - nsCOMPtr selCon; - result = GetSelectionController(aPresContext, getter_AddRefs(selCon)); - //get the selection controller - if (NS_SUCCEEDED(result) && selCon) - { - PRInt16 displayresult; - selCon->GetDisplaySelection(&displayresult); - if (displayresult == nsISelectionController::SELECTION_OFF) - return NS_OK;//nothing to do we cannot affect selection from here - } - nsCOMPtr frameselection; - shell->GetFrameSelection(getter_AddRefs(frameselection)); - if (frameselection) - result = frameselection->HandleClick(pos.mResultContent, pos.mContentOffset, - pos.mContentOffsetEnd, me->isShift, PR_FALSE, pos.mPreferLeft); - } - else - result = resultFrame->HandleEvent(aPresContext, aEvent, aEventStatus);//else let the frame/container do what it needs - if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN && !IsMouseCaptured(aPresContext)) - CaptureMouse(aPresContext, PR_TRUE); - return result; - } - else - { - /*we have to add this because any frame that overrides nsFrame::HandleEvent for mouse down MUST capture the mouse events!! - if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN && !IsMouseCaptured(aPresContext)) - CaptureMouse(aPresContext, PR_TRUE);*/ - return NS_OK; //just stop it - } - } - return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); -} - - -NS_IMETHODIMP -nsBlockFrame::GetFrameForPoint(nsIPresContext* aPresContext, - const nsPoint& aPoint, - nsFramePaintLayer aWhichLayer, - nsIFrame** aFrame) -{ - nsresult rv; - - switch (aWhichLayer) { - case NS_FRAME_PAINT_LAYER_FOREGROUND: - rv = GetFrameForPointUsing(aPresContext, aPoint, nsnull, NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE, aFrame); - if (NS_OK == rv) { - return NS_OK; - } - if (nsnull != mBullet) { - rv = GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::bulletList, NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE, aFrame); - } - return rv; - break; - - case NS_FRAME_PAINT_LAYER_FLOATERS: - // we painted our floaters before our children, and thus - // we should check floaters within children first - rv = GetFrameForPointUsing(aPresContext, aPoint, nsnull, NS_FRAME_PAINT_LAYER_FLOATERS, PR_FALSE, aFrame); - if (NS_OK == rv) { - return NS_OK; - } - if (mFloaters.NotEmpty()) { - - rv = GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::floaterList, NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE, aFrame); - if (NS_OK == rv) { - return NS_OK; - } - - rv = GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::floaterList, NS_FRAME_PAINT_LAYER_FLOATERS, PR_FALSE, aFrame); - if (NS_OK == rv) { - return NS_OK; - } - - return GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::floaterList, NS_FRAME_PAINT_LAYER_BACKGROUND, PR_FALSE, aFrame); - - } else { - return NS_ERROR_FAILURE; - } - break; - - case NS_FRAME_PAINT_LAYER_BACKGROUND: - // we're a block, so PR_TRUE for consider self - return GetFrameForPointUsing(aPresContext, aPoint, nsnull, NS_FRAME_PAINT_LAYER_BACKGROUND, PR_TRUE, aFrame); - break; - } - // we shouldn't get here - NS_ASSERTION(PR_FALSE, "aWhichLayer was not understood"); - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsBlockFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) -{ - if (aChild) { - // See if the child is absolutely positioned - nsFrameState childState; - aChild->GetFrameState(&childState); - if (childState & NS_FRAME_OUT_OF_FLOW) { - const nsStylePosition* position; - aChild->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)position); - - if (position->IsAbsolutelyPositioned()) { - // Generate a reflow command to reflow our dirty absolutely - // positioned child frames. - // XXX Note that we don't currently try and coalesce the reflow commands, - // although we should. We can't use the NS_FRAME_HAS_DIRTY_CHILDREN - // flag, because that's used to indicate whether in-flow children are - // dirty... - nsIReflowCommand* reflowCmd; - nsresult rv = NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - reflowCmd->SetChildListName(nsLayoutAtoms::absoluteList); - aPresShell->AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - return rv; - } - } - - // Mark the line containing the child frame dirty. - PRBool isFloater; - nsLineBox* prevLine; - nsLineBox* line = FindLineFor(aChild, &prevLine, &isFloater); - - if (!isFloater) { - if (line) - MarkLineDirty(line, prevLine); - } - else { - line = mLines; - while (nsnull != line) { - line->MarkDirty(); - line = line->mNext; - } - } - } - - // Either generate a reflow command to reflow the dirty child or - // coalesce this reflow request with an existing reflow command - if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) { - // If this is the first dirty child, - // post a dirty children reflow command targeted at yourself - mState |= NS_FRAME_HAS_DIRTY_CHILDREN; - - nsFrame::CreateAndPostReflowCommand(aPresShell, this, - nsIReflowCommand::ReflowDirty, nsnull, nsnull, nsnull); - } - else { - if (!(mState & NS_FRAME_IS_DIRTY)) { - // Mark yourself as dirty - mState |= NS_FRAME_IS_DIRTY; - - // Cancel the dirty children reflow command you posted earlier - nsIReflowCommand::ReflowType type = nsIReflowCommand::ReflowDirty; - aPresShell->CancelReflowCommand(this, &type); - - // Pass up the reflow request to the parent frame. - mParent->ReflowDirtyChild(aPresShell, this); - } - } - - return NS_OK; -} - -////////////////////////////////////////////////////////////////////// -// Debugging - -#ifdef NS_DEBUG -static PRBool -InLineList(nsLineBox* aLines, nsIFrame* aFrame) -{ - while (nsnull != aLines) { - nsIFrame* frame = aLines->mFirstChild; - PRInt32 n = aLines->GetChildCount(); - while (--n >= 0) { - if (frame == aFrame) { - return PR_TRUE; - } - frame->GetNextSibling(&frame); - } - aLines = aLines->mNext; - } - return PR_FALSE; -} - -static PRBool -InSiblingList(nsLineBox* aLine, nsIFrame* aFrame) -{ - if (nsnull != aLine) { - nsIFrame* frame = aLine->mFirstChild; - while (nsnull != frame) { - if (frame == aFrame) { - return PR_TRUE; - } - frame->GetNextSibling(&frame); - } - } - return PR_FALSE; -} - -PRBool -nsBlockFrame::IsChild(nsIPresContext* aPresContext, nsIFrame* aFrame) -{ - nsIFrame* parent; - aFrame->GetParent(&parent); - if (parent != (nsIFrame*)this) { - return PR_FALSE; - } - if (InLineList(mLines, aFrame) && InSiblingList(mLines, aFrame)) { - return PR_TRUE; - } - nsLineBox* overflowLines = GetOverflowLines(aPresContext, PR_FALSE); - if (InLineList(overflowLines, aFrame) && InSiblingList(overflowLines, aFrame)) { - return PR_TRUE; - } - return PR_FALSE; -} - -NS_IMETHODIMP -nsBlockFrame::VerifyTree() const -{ - // XXX rewrite this - return NS_OK; -} - -NS_IMETHODIMP -nsBlockFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const -{ - if (!aHandler || !aResult) { - return NS_ERROR_NULL_POINTER; - } - - PRUint32 sum = sizeof(*this); - - // Add in size of each line object - nsLineBox* line = mLines; - while (line) { - PRUint32 lineBoxSize; - nsIAtom* atom = line->SizeOf(aHandler, &lineBoxSize); - aHandler->AddSize(atom, lineBoxSize); - line = line->mNext; - } - - *aResult = sum; - return NS_OK; -} -#endif - -//---------------------------------------------------------------------- - -NS_IMETHODIMP -nsBlockFrame::Init(nsIPresContext* aPresContext, - nsIContent* aContent, - nsIFrame* aParent, - nsIStyleContext* aContext, - nsIFrame* aPrevInFlow) -{ - if (aPrevInFlow) { - // Copy over the block/area frame type flags - nsBlockFrame* blockFrame = (nsBlockFrame*)aPrevInFlow; - - SetFlags(blockFrame->mState & NS_BLOCK_FLAGS_MASK); - } - - nsresult rv = nsBlockFrameSuper::Init(aPresContext, aContent, aParent, - aContext, aPrevInFlow); - return rv; -} - -nsIStyleContext* -nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext) -{ - nsIStyleContext* fls; - aPresContext->ProbePseudoStyleContextFor(mContent, - nsHTMLAtoms::firstLetterPseudo, - mStyleContext, PR_FALSE, &fls); - return fls; -} - -NS_IMETHODIMP -nsBlockFrame::SetInitialChildList(nsIPresContext* aPresContext, - nsIAtom* aListName, - nsIFrame* aChildList) -{ - nsresult rv = NS_OK; - - if (nsLayoutAtoms::absoluteList == aListName) { - mAbsoluteContainer.SetInitialChildList(this, aPresContext, aListName, aChildList); - } - else if (nsLayoutAtoms::floaterList == aListName) { - mFloaters.SetFrames(aChildList); - } - else { - - // Lookup up the two pseudo style contexts - if (nsnull == mPrevInFlow) { - nsIStyleContext* firstLetterStyle = GetFirstLetterStyle(aPresContext); - if (nsnull != firstLetterStyle) { - mState |= NS_BLOCK_HAS_FIRST_LETTER_STYLE; -#ifdef NOISY_FIRST_LETTER - ListTag(stdout); - printf(": first-letter style found\n"); -#endif - NS_RELEASE(firstLetterStyle); - } - } - - rv = AddFrames(aPresContext, aChildList, nsnull); - if (NS_FAILED(rv)) { - return rv; - } - - // Create list bullet if this is a list-item. Note that this is done - // here so that RenumberLists will work (it needs the bullets to - // store the bullet numbers). - const nsStyleDisplay* styleDisplay; - GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay); - if ((nsnull == mPrevInFlow) && - (NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) && - (nsnull == mBullet)) { - // Resolve style for the bullet frame - nsIStyleContext* kidSC; - aPresContext->ResolvePseudoStyleContextFor(mContent, - nsHTMLAtoms::mozListBulletPseudo, - mStyleContext, PR_FALSE, &kidSC); - - // Create bullet frame - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - mBullet = new (shell.get()) nsBulletFrame; - - if (nsnull == mBullet) { - NS_RELEASE(kidSC); - return NS_ERROR_OUT_OF_MEMORY; - } - mBullet->Init(aPresContext, mContent, this, kidSC, nsnull); - NS_RELEASE(kidSC); - - // If the list bullet frame should be positioned inside then add - // it to the flow now. - const nsStyleList* styleList; - GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList); - if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == - styleList->mListStylePosition) { - AddFrames(aPresContext, mBullet, nsnull); - mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; - } - else { - mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; - } - } - } - - return NS_OK; -} - -PRBool -nsBlockFrame::FrameStartsCounterScope(nsIFrame* aFrame) -{ - const nsStyleContent* styleContent; - aFrame->GetStyleData(eStyleStruct_Content, - (const nsStyleStruct*&) styleContent); - if (0 != styleContent->CounterResetCount()) { - // Winner - return PR_TRUE; - } - return PR_FALSE; -} - -void -nsBlockFrame::RenumberLists(nsIPresContext* aPresContext) -{ - if (!FrameStartsCounterScope(this)) { - // If this frame doesn't start a counter scope then we don't need - // to renumber child list items. - return; - } - - // Setup initial list ordinal value - // XXX Map html's start property to counter-reset style - PRInt32 ordinal = 1; - nsIHTMLContent* hc; - if (mContent && (NS_OK == mContent->QueryInterface(kIHTMLContentIID, (void**) &hc))) { - nsHTMLValue value; - if (NS_CONTENT_ATTR_HAS_VALUE == - hc->GetHTMLAttribute(nsHTMLAtoms::start, value)) { - if (eHTMLUnit_Integer == value.GetUnit()) { - ordinal = value.GetIntValue(); - if (ordinal <= 0) { - ordinal = 1; - } - } - } - NS_RELEASE(hc); - } - - // Get to first-in-flow - nsBlockFrame* block = (nsBlockFrame*) GetFirstInFlow(); - RenumberListsInBlock(aPresContext, block, &ordinal, 0); -} - -PRBool -nsBlockFrame::RenumberListsInBlock(nsIPresContext* aPresContext, - nsBlockFrame* aBlockFrame, - PRInt32* aOrdinal, - PRInt32 aDepth) -{ - PRBool renumberedABullet = PR_FALSE; - - while (nsnull != aBlockFrame) { - // Examine each line in the block - nsLineBox* line = aBlockFrame->mLines; - while (line) { - nsIFrame* kid = line->mFirstChild; - PRInt32 n = line->GetChildCount(); - while (--n >= 0) { - PRBool kidRenumberedABullet = RenumberListsFor(aPresContext, kid, aOrdinal, aDepth); - if (kidRenumberedABullet) { - line->MarkDirty(); - renumberedABullet = PR_TRUE; - } - kid->GetNextSibling(&kid); - } - line = line->mNext; - } - - // Advance to the next continuation - aBlockFrame->GetNextInFlow((nsIFrame**) &aBlockFrame); - } - - return renumberedABullet; -} - -// XXX temporary code: after ib work is done in frame construction -// code this can be removed. -PRBool -nsBlockFrame::RenumberListsIn(nsIPresContext* aPresContext, - nsIFrame* aContainerFrame, - PRInt32* aOrdinal, - PRInt32 aDepth) -{ - PRBool renumberedABullet = PR_FALSE; - - // For each flow-block... - while (nsnull != aContainerFrame) { - // For each frame in the flow-block... - nsIFrame* kid; - aContainerFrame->FirstChild(aPresContext, nsnull, &kid); - while (nsnull != kid) { - PRBool kidRenumberedABullet = RenumberListsFor(aPresContext, kid, aOrdinal, aDepth); - if (kidRenumberedABullet) { - renumberedABullet = PR_TRUE; - } - kid->GetNextSibling(&kid); - } - aContainerFrame->GetNextInFlow(&aContainerFrame); - } - return renumberedABullet; -} - -PRBool -nsBlockFrame::RenumberListsFor(nsIPresContext* aPresContext, - nsIFrame* aKid, - PRInt32* aOrdinal, - PRInt32 aDepth) -{ - NS_ASSERTION(aPresContext && aKid && aOrdinal, "null params are immoral!"); - - // add in a sanity check for absurdly deep frame trees. See bug 42138 - if (MAX_DEPTH_FOR_LIST_RENUMBERING < aDepth) - return PR_FALSE; - - PRBool kidRenumberedABullet = PR_FALSE; - nsIFrame* kid = aKid; - - // if the frame is a placeholder, then get the out of flow frame - nsCOMPtr frameType; - aKid->GetFrameType(getter_AddRefs(frameType)); - if (nsLayoutAtoms::placeholderFrame == frameType.get()) { - kid = NS_STATIC_CAST(nsPlaceholderFrame*, aKid)->GetOutOfFlowFrame(); - NS_ASSERTION(kid, "no out-of-flow frame"); - } - - // If the frame is a list-item and the frame implements our - // block frame API then get it's bullet and set the list item - // ordinal. - const nsStyleDisplay* display; - kid->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) { - // Make certain that the frame isa block-frame in case - // something foreign has crept in. - nsBlockFrame* listItem; - nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**)&listItem); - if (NS_SUCCEEDED(rv)) { - if (nsnull != listItem->mBullet) { - PRBool changed; - *aOrdinal = listItem->mBullet->SetListItemOrdinal(*aOrdinal, - &changed); - if (changed) { - kidRenumberedABullet = PR_TRUE; - } - } - - // XXX temporary? if the list-item has child list-items they - // should be numbered too; especially since the list-item is - // itself (ASSUMED!) not to be a counter-reseter. - PRBool meToo = RenumberListsInBlock(aPresContext, listItem, aOrdinal, aDepth + 1); - if (meToo) { - kidRenumberedABullet = PR_TRUE; - } - } - } - else if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) { - if (FrameStartsCounterScope(kid)) { - // Don't bother recursing into a block frame that is a new - // counter scope. Any list-items in there will be handled by - // it. - } - else { - // If the display=block element ISA block-frame then go - // ahead and recurse into it as it might have child - // list-items. - nsBlockFrame* kidBlock; - nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**) &kidBlock); - if (NS_SUCCEEDED(rv)) { - kidRenumberedABullet = RenumberListsInBlock(aPresContext, kidBlock, aOrdinal, aDepth + 1); - } - } - } else if (NS_STYLE_DISPLAY_INLINE == display->mDisplay) { - // XXX temporary code: after ib work is done in frame construction - // code this can be removed. - - // If the display=inline element ISA nsInlineFrame then go - // ahead and recurse into it as it might have child - // list-items. - nsInlineFrame* kidInline; - nsresult rv = kid->QueryInterface(nsInlineFrame::kInlineFrameCID, - (void**) &kidInline); - if (NS_SUCCEEDED(rv)) { - kidRenumberedABullet = RenumberListsIn(aPresContext, kid, aOrdinal, aDepth + 1); - } - } - return kidRenumberedABullet; -} - -void -nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, - nsHTMLReflowMetrics& aMetrics) -{ - // Reflow the bullet now - nsSize availSize; - availSize.width = NS_UNCONSTRAINEDSIZE; - availSize.height = NS_UNCONSTRAINEDSIZE; - nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState, - mBullet, availSize); - nsReflowStatus status; - mBullet->WillReflow(aState.mPresContext); - mBullet->Reflow(aState.mPresContext, aMetrics, reflowState, status); - -#ifdef IBMBIDI - const nsStyleDisplay* display; - GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); -#endif // IBMBIDI - // Place the bullet now; use its right margin to distance it - // from the rest of the frames in the line - nscoord x = -#ifdef IBMBIDI - // For direction RTL: set x to the right margin for now. - // This value will be used to indent the bullet from the right most - // egde of the previous frame in nsLineLayout::HorizontalAlignFrames. - (NS_STYLE_DIRECTION_RTL == display->mDirection) - ? reflowState.mComputedMargin.right : -#endif // IBMBIDI - - reflowState.mComputedMargin.right - aMetrics.width; - - // Approximate the bullets position; vertical alignment will provide - // the final vertical location. - const nsMargin& bp = aState.BorderPadding(); - nscoord y = bp.top; - mBullet->SetRect(aState.mPresContext, nsRect(x, y, aMetrics.width, aMetrics.height)); - mBullet->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED); -} - -//XXX get rid of this -- its slow -void -nsBlockFrame::BuildFloaterList() -{ - nsIFrame* head = nsnull; - nsIFrame* current = nsnull; - nsLineBox* line = mLines; - while (nsnull != line) { - if (line->HasFloaters()) { - nsFloaterCache* fc = line->GetFirstFloater(); - while (fc) { - nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame(); - if (nsnull == head) { - current = head = floater; - } - else { - current->SetNextSibling(floater); - current = floater; - } - fc = fc->Next(); - } - } - line = line->mNext; - } - - // Terminate end of floater list just in case a floater was removed - if (nsnull != current) { - current->SetNextSibling(nsnull); - } - mFloaters.SetFrames(head); -} - -// XXX keep the text-run data in the first-in-flow of the block - -#ifdef DEBUG -void -nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) -{ - if (!gVerifyLines) { - return; - } - nsLineBox* line = mLines; - if (!line) { - return; - } - - // Add up the counts on each line. Also validate that IsFirstLine is - // set properly. - PRInt32 count = 0; - PRBool seenBlock = PR_FALSE; - while (nsnull != line) { - if (aFinalCheckOK) { - NS_ABORT_IF_FALSE(line->GetChildCount(), "empty line"); - if (line->IsBlock()) { - seenBlock = PR_TRUE; - } - if (line->IsBlock()) { - NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); - } - } - count += line->GetChildCount(); - line = line->mNext; - } - - // Then count the frames - PRInt32 frameCount = 0; - nsIFrame* frame = mLines->mFirstChild; - while (nsnull != frame) { - frameCount++; - frame->GetNextSibling(&frame); - } - NS_ASSERTION(count == frameCount, "bad line list"); - - // Next: test that each line has right number of frames on it - line = mLines; - nsLineBox* prevLine = nsnull; - while (nsnull != line) { - count = line->GetChildCount(); - frame = line->mFirstChild; - while (--count >= 0) { - frame->GetNextSibling(&frame); - } - prevLine = line; - line = line->mNext; - if ((nsnull != line) && (0 != line->GetChildCount())) { - NS_ASSERTION(frame == line->mFirstChild, "bad line list"); - } - } -} - -// Its possible that a frame can have some frames on an overflow -// list. But its never possible for multiple frames to have overflow -// lists. Check that this fact is actually true. -void -nsBlockFrame::VerifyOverflowSituation(nsIPresContext* aPresContext) -{ - nsBlockFrame* flow = (nsBlockFrame*) GetFirstInFlow(); - while (nsnull != flow) { - nsLineBox* overflowLines = GetOverflowLines(aPresContext, PR_FALSE); - if (nsnull != overflowLines) { - NS_ASSERTION(nsnull != overflowLines->mFirstChild, - "bad overflow list"); - } - flow = (nsBlockFrame*) flow->mNextInFlow; - } -} - -PRInt32 -nsBlockFrame::GetDepth() const -{ - PRInt32 depth = 0; - nsIFrame* parent = mParent; - while (nsnull != parent) { - parent->GetParent(&parent); - depth++; - } - return depth; -} -#endif