NS_IMETHODIMP nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { NS_PRECONDITION(aPresContext->IsRootPaginatedDocument(), "A Page Sequence is only for real pages"); DO_GLOBAL_REFLOW_COUNT("nsSimplePageSequenceFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE_REFLOW_IN("nsSimplePageSequenceFrame::Reflow"); aStatus = NS_FRAME_COMPLETE; // we're always complete // Don't do incremental reflow until we've taught tables how to do // it right in paginated mode. if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // Return our desired size aDesiredSize.height = mSize.height * PresContext()->GetPrintPreviewScale(); aDesiredSize.width = mSize.width * PresContext()->GetPrintPreviewScale(); aDesiredSize.SetOverflowAreasToDesiredBounds(); FinishAndStoreOverflow(&aDesiredSize); return NS_OK; } PRBool isPrintPreview = aPresContext->Type() == nsPresContext::eContext_PrintPreview; // See if we can get a Print Settings from the Context if (!mPageData->mPrintSettings && aPresContext->Medium() == nsGkAtoms::print) { mPageData->mPrintSettings = aPresContext->GetPrintSettings(); } // now get out margins & edges if (mPageData->mPrintSettings) { nsIntMargin unwriteableTwips; mPageData->mPrintSettings->GetUnwriteableMarginInTwips(unwriteableTwips); NS_ASSERTION(unwriteableTwips.left >= 0 && unwriteableTwips.top >= 0 && unwriteableTwips.right >= 0 && unwriteableTwips.bottom >= 0, "Unwriteable twips should be non-negative"); nsIntMargin marginTwips; mPageData->mPrintSettings->GetMarginInTwips(marginTwips); mMargin = aPresContext->CSSTwipsToAppUnits(marginTwips + unwriteableTwips); PRInt16 printType; mPageData->mPrintSettings->GetPrintRange(&printType); mPrintRangeType = printType; nsIntMargin edgeTwips; mPageData->mPrintSettings->GetEdgeInTwips(edgeTwips); // sanity check the values. three inches are sometimes needed PRInt32 inchInTwips = NS_INCHES_TO_INT_TWIPS(3.0); edgeTwips.top = NS_MIN(NS_MAX(edgeTwips.top, 0), inchInTwips); edgeTwips.bottom = NS_MIN(NS_MAX(edgeTwips.bottom, 0), inchInTwips); edgeTwips.left = NS_MIN(NS_MAX(edgeTwips.left, 0), inchInTwips); edgeTwips.right = NS_MIN(NS_MAX(edgeTwips.right, 0), inchInTwips); mPageData->mEdgePaperMargin = aPresContext->CSSTwipsToAppUnits(edgeTwips + unwriteableTwips); } // *** Special Override *** // If this is a sub-sdoc (meaning it doesn't take the whole page) // and if this Document is in the upper left hand corner // we need to suppress the top margin or it will reflow too small nsSize pageSize = aPresContext->GetPageSize(); mPageData->mReflowSize = pageSize; // If we're printing a selection, we need to reflow with // unconstrained height, to make sure we'll get to the selection // even if it's beyond the first page of content. if (nsIPrintSettings::kRangeSelection == mPrintRangeType) { mPageData->mReflowSize.height = NS_UNCONSTRAINEDSIZE; } mPageData->mReflowMargin = mMargin; // Compute the size of each page and the x coordinate that each page will // be placed at nscoord extraThreshold = NS_MAX(pageSize.width, pageSize.height)/10; PRInt32 gapInTwips = nsContentUtils::GetIntPref("print.print_extra_margin"); gapInTwips = NS_MAX(0, gapInTwips); nscoord extraGap = aPresContext->CSSTwipsToAppUnits(gapInTwips); extraGap = NS_MIN(extraGap, extraThreshold); // clamp to 1/10 of the largest dim of the page nscoord deadSpaceGap = 0; if (isPrintPreview) { GetDeadSpaceValue(&gapInTwips); deadSpaceGap = aPresContext->CSSTwipsToAppUnits(gapInTwips); } nsMargin extraMargin(0,0,0,0); nsSize shadowSize(0,0); if (aPresContext->IsScreen()) { extraMargin.SizeTo(extraGap, extraGap, extraGap, extraGap); nscoord fourPixels = nsPresContext::CSSPixelsToAppUnits(4); shadowSize.SizeTo(fourPixels, fourPixels); } mPageData->mShadowSize = shadowSize; mPageData->mExtraMargin = extraMargin; const nscoord x = deadSpaceGap; nscoord y = deadSpaceGap;// Running y-offset for each page nsSize availSize(pageSize.width + shadowSize.width + extraMargin.LeftRight(), pageSize.height + shadowSize.height + extraMargin.TopBottom()); // Tile the pages vertically nsHTMLReflowMetrics kidSize; for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; ) { // Set the shared data into the page frame before reflow nsPageFrame * pf = static_cast<nsPageFrame*>(kidFrame); pf->SetSharedPageData(mPageData); // Reflow the page nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, availSize); nsReflowStatus status; kidReflowState.SetComputedWidth(kidReflowState.availableWidth); //kidReflowState.SetComputedHeight(kidReflowState.availableHeight); PR_PL(("AV W: %d H: %d\n", kidReflowState.availableWidth, kidReflowState.availableHeight)); // Place and size the page. If the page is narrower than our // max width then center it horizontally ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, x, y, 0, status); FinishReflowChild(kidFrame, aPresContext, nsnull, kidSize, x, y, 0); y += kidSize.height; // Leave a slight gap between the pages y += deadSpaceGap; // Is the page complete? nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); if (NS_FRAME_IS_FULLY_COMPLETE(status)) { NS_ASSERTION(!kidNextInFlow, "bad child flow list"); } else if (!kidNextInFlow) { // The page isn't complete and it doesn't have a next-in-flow, so // create a continuing page. nsIFrame* continuingPage; nsresult rv = aPresContext->PresShell()->FrameConstructor()-> CreateContinuingFrame(aPresContext, kidFrame, this, &continuingPage); if (NS_FAILED(rv)) { break; } // Add it to our child list mFrames.InsertFrame(nsnull, kidFrame, continuingPage); } // Get the next page kidFrame = kidFrame->GetNextSibling(); } // Get Total Page Count nsIFrame* page; PRInt32 pageTot = 0; for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) { pageTot++; } // Set Page Number Info PRInt32 pageNum = 1; for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) { nsPageFrame * pf = static_cast<nsPageFrame*>(page); if (pf != nsnull) { pf->SetPageNumInfo(pageNum, pageTot); } pageNum++; } // Create current Date/Time String if (!mDateFormatter) mDateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID); NS_ENSURE_TRUE(mDateFormatter, NS_ERROR_FAILURE); nsAutoString formattedDateString; time_t ltime; time( <ime ); if (NS_SUCCEEDED(mDateFormatter->FormatTime(nsnull /* nsILocale* locale */, kDateFormatShort, kTimeFormatNoSeconds, ltime, formattedDateString))) { PRUnichar * uStr = ToNewUnicode(formattedDateString); SetDateTimeStr(uStr); // memory will be freed } // Return our desired size // Adjustr the reflow size by PrintPreviewScale so the scrollbars end up the // correct size nscoord w = (x + availSize.width + deadSpaceGap); aDesiredSize.height = y * PresContext()->GetPrintPreviewScale(); // includes page heights and dead space aDesiredSize.width = w * PresContext()->GetPrintPreviewScale(); aDesiredSize.SetOverflowAreasToDesiredBounds(); FinishAndStoreOverflow(&aDesiredSize); // cache the size so we can set the desired size // for the other reflows that happen mSize.width = w; mSize.height = y; NS_FRAME_TRACE_REFLOW_OUT("nsSimplePageSequeceFrame::Reflow", aStatus); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
bool nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus, const ReflowConfig& aConfig, bool aUnboundedLastColumn, nsCollapsingMargin* aBottomMarginCarriedOut, ColumnBalanceData& aColData) { aColData.Reset(); bool allFit = true; bool RTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; bool shrinkingHeightOnly = !NS_SUBTREE_DIRTY(this) && mLastBalanceHeight > aConfig.mColMaxHeight; #ifdef DEBUG_roc printf("*** Doing column reflow pass: mLastBalanceHeight=%d, mColMaxHeight=%d, RTL=%d\n, mBalanceColCount=%d, mColWidth=%d, mColGap=%d\n", mLastBalanceHeight, aConfig.mColMaxHeight, RTL, aConfig.mBalanceColCount, aConfig.mColWidth, aConfig.mColGap); #endif DrainOverflowColumns(); if (mLastBalanceHeight != aConfig.mColMaxHeight) { mLastBalanceHeight = aConfig.mColMaxHeight; // XXX Seems like this could fire if incremental reflow pushed the column set // down so we reflow incrementally with a different available height. // We need a way to do an incremental reflow and be sure availableHeight // changes are taken account of! Right now I think block frames with absolute // children might exit early. //NS_ASSERTION(aKidReason != eReflowReason_Incremental, // "incremental reflow should not have changed the balance height"); } // get our border and padding const nsMargin &borderPadding = aReflowState.mComputedBorderPadding; nsRect contentRect(0, 0, 0, 0); nsOverflowAreas overflowRects; nsIFrame* child = mFrames.FirstChild(); nsPoint childOrigin = nsPoint(borderPadding.left, borderPadding.top); // For RTL, figure out where the last column's left edge should be. Since the // columns might not fill the frame exactly, we need to account for the // slop. Otherwise we'll waste time moving the columns by some tiny // amount unnecessarily. nscoord targetX = borderPadding.left; if (RTL) { nscoord availWidth = aReflowState.availableWidth; if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) { availWidth = aReflowState.ComputedWidth(); } if (availWidth != NS_INTRINSICSIZE) { childOrigin.x += availWidth - aConfig.mColWidth; targetX += aConfig.mExpectedWidthLeftOver; #ifdef DEBUG_roc printf("*** childOrigin.x = %d\n", childOrigin.x); #endif } } int columnCount = 0; int contentBottom = 0; bool reflowNext = false; while (child) { // Try to skip reflowing the child. We can't skip if the child is dirty. We also can't // skip if the next column is dirty, because the next column's first line(s) // might be pullable back to this column. We can't skip if it's the last child // because we need to obtain the bottom margin. We can't skip // if this is the last column and we're supposed to assign unbounded // height to it, because that could change the available height from // the last time we reflowed it and we should try to pull all the // content from its next sibling. (Note that it might be the last // column, but not be the last child because the desired number of columns // has changed.) bool skipIncremental = !aReflowState.ShouldReflowAllKids() && !NS_SUBTREE_DIRTY(child) && child->GetNextSibling() && !(aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) && !NS_SUBTREE_DIRTY(child->GetNextSibling()); // If we need to pull up content from the prev-in-flow then this is not just // a height shrink. The prev in flow will have set the dirty bit. // Check the overflow rect YMost instead of just the child's content height. The child // may have overflowing content that cares about the available height boundary. // (It may also have overflowing content that doesn't care about the available height // boundary, but if so, too bad, this optimization is defeated.) // We want scrollable overflow here since this is a calculation that // affects layout. bool skipResizeHeightShrink = shrinkingHeightOnly && child->GetScrollableOverflowRect().YMost() <= aConfig.mColMaxHeight; nscoord childContentBottom = 0; if (!reflowNext && (skipIncremental || skipResizeHeightShrink)) { // This child does not need to be reflowed, but we may need to move it MoveChildTo(this, child, childOrigin); // If this is the last frame then make sure we get the right status nsIFrame* kidNext = child->GetNextSibling(); if (kidNext) { aStatus = (kidNext->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) ? NS_FRAME_OVERFLOW_INCOMPLETE : NS_FRAME_NOT_COMPLETE; } else { aStatus = mLastFrameStatus; } childContentBottom = nsLayoutUtils::CalculateContentBottom(child); #ifdef DEBUG_roc printf("*** Skipping child #%d %p (incremental %d, resize height shrink %d): status = %d\n", columnCount, (void*)child, skipIncremental, skipResizeHeightShrink, aStatus); #endif } else { nsSize availSize(aConfig.mColWidth, aConfig.mColMaxHeight); if (aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) { availSize.height = GetAvailableContentHeight(aReflowState); } if (reflowNext) child->AddStateBits(NS_FRAME_IS_DIRTY); nsHTMLReflowState kidReflowState(PresContext(), aReflowState, child, availSize, availSize.width, aReflowState.ComputedHeight()); kidReflowState.mFlags.mIsTopOfPage = PR_TRUE; kidReflowState.mFlags.mTableIsSplittable = PR_FALSE; #ifdef DEBUG_roc printf("*** Reflowing child #%d %p: availHeight=%d\n", columnCount, (void*)child,availSize.height); #endif // Note if the column's next in flow is not being changed by this incremental reflow. // This may allow the current column to avoid trying to pull lines from the next column. if (child->GetNextSibling() && !(GetStateBits() & NS_FRAME_IS_DIRTY) && !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY)) { kidReflowState.mFlags.mNextInFlowUntouched = PR_TRUE; } nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mFlags); // XXX it would be cool to consult the float manager for the // previous block to figure out the region of floats from the // previous column that extend into this column, and subtract // that region from the new float manager. So you could stick a // really big float in the first column and text in following // columns would flow around it. // Reflow the frame ReflowChild(child, PresContext(), kidDesiredSize, kidReflowState, childOrigin.x + kidReflowState.mComputedMargin.left, childOrigin.y + kidReflowState.mComputedMargin.top, 0, aStatus); reflowNext = (aStatus & NS_FRAME_REFLOW_NEXTINFLOW) != 0; #ifdef DEBUG_roc printf("*** Reflowed child #%d %p: status = %d, desiredSize=%d,%d\n", columnCount, (void*)child, aStatus, kidDesiredSize.width, kidDesiredSize.height); #endif NS_FRAME_TRACE_REFLOW_OUT("Column::Reflow", aStatus); *aBottomMarginCarriedOut = kidDesiredSize.mCarriedOutBottomMargin; FinishReflowChild(child, PresContext(), &kidReflowState, kidDesiredSize, childOrigin.x, childOrigin.y, 0); childContentBottom = nsLayoutUtils::CalculateContentBottom(child); if (childContentBottom > aConfig.mColMaxHeight) { allFit = PR_FALSE; } if (childContentBottom > availSize.height) { aColData.mMaxOverflowingHeight = NS_MAX(childContentBottom, aColData.mMaxOverflowingHeight); } } contentRect.UnionRect(contentRect, child->GetRect()); ConsiderChildOverflow(overflowRects, child); contentBottom = NS_MAX(contentBottom, childContentBottom); aColData.mLastHeight = childContentBottom; aColData.mSumHeight += childContentBottom; // Build a continuation column if necessary nsIFrame* kidNextInFlow = child->GetNextInFlow(); if (NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)) { NS_ASSERTION(!kidNextInFlow, "next in flow should have been deleted"); child = nsnull; break; } else { ++columnCount; // Make sure that the column has a next-in-flow. If not, we must // create one to hold the overflowing stuff, even if we're just // going to put it on our overflow list and let *our* // next in flow handle it. if (!kidNextInFlow) { NS_ASSERTION(aStatus & NS_FRAME_REFLOW_NEXTINFLOW, "We have to create a continuation, but the block doesn't want us to reflow it?"); // We need to create a continuing column nsresult rv = CreateNextInFlow(PresContext(), child, kidNextInFlow); if (NS_FAILED(rv)) { NS_NOTREACHED("Couldn't create continuation"); child = nsnull; break; } } // Make sure we reflow a next-in-flow when it switches between being // normal or overflow container if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { if (!(kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) { aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; reflowNext = PR_TRUE; kidNextInFlow->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); } } else if (kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) { aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; reflowNext = PR_TRUE; kidNextInFlow->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); } if (columnCount >= aConfig.mBalanceColCount) { // No more columns allowed here. Stop. aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; kidNextInFlow->AddStateBits(NS_FRAME_IS_DIRTY); // Move any of our leftover columns to our overflow list. Our // next-in-flow will eventually pick them up. const nsFrameList& continuationColumns = mFrames.RemoveFramesAfter(child); if (continuationColumns.NotEmpty()) { SetOverflowFrames(PresContext(), continuationColumns); } child = nsnull; break; } } if (PresContext()->HasPendingInterrupt()) { // Stop the loop now while |child| still points to the frame that bailed // out. We could keep going here and condition a bunch of the code in // this loop on whether there's an interrupt, or even just keep going and // trying to reflow the blocks (even though we know they'll interrupt // right after their first line), but stopping now is conceptually the // simplest (and probably fastest) thing. break; } // Advance to the next column child = child->GetNextSibling(); if (child) { if (!RTL) { childOrigin.x += aConfig.mColWidth + aConfig.mColGap; } else { childOrigin.x -= aConfig.mColWidth + aConfig.mColGap; } #ifdef DEBUG_roc printf("*** NEXT CHILD ORIGIN.x = %d\n", childOrigin.x); #endif } } if (PresContext()->CheckForInterrupt(this) && (GetStateBits() & NS_FRAME_IS_DIRTY)) { // Mark all our kids starting with |child| dirty // Note that this is a CheckForInterrupt call, not a HasPendingInterrupt, // because we might have interrupted while reflowing |child|, and since // we're about to add a dirty bit to |child| we need to make sure that // |this| is scheduled to have dirty bits marked on it and its ancestors. // Otherwise, when we go to mark dirty bits on |child|'s ancestors we'll // bail out immediately, since it'll already have a dirty bit. for (; child; child = child->GetNextSibling()) { child->AddStateBits(NS_FRAME_IS_DIRTY); } } // If we're doing RTL, we need to make sure our last column is at the left-hand side of the frame. if (RTL && childOrigin.x != targetX) { overflowRects.Clear(); contentRect = nsRect(0, 0, 0, 0); PRInt32 deltaX = targetX - childOrigin.x; #ifdef DEBUG_roc printf("*** CHILDORIGIN.x = %d, targetX = %d, DELTAX = %d\n", childOrigin.x, targetX, deltaX); #endif for (child = mFrames.FirstChild(); child; child = child->GetNextSibling()) { MoveChildTo(this, child, child->GetPosition() + nsPoint(deltaX, 0)); ConsiderChildOverflow(overflowRects, child); contentRect.UnionRect(contentRect, child->GetRect()); } } aColData.mMaxHeight = contentBottom; contentRect.height = NS_MAX(contentRect.height, contentBottom); mLastFrameStatus = aStatus; // contentRect included the borderPadding.left,borderPadding.top of the child rects contentRect -= nsPoint(borderPadding.left, borderPadding.top); nsSize contentSize = nsSize(contentRect.XMost(), contentRect.YMost()); // Apply computed and min/max values if (aReflowState.ComputedHeight() != NS_INTRINSICSIZE) { contentSize.height = aReflowState.ComputedHeight(); } else { if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxHeight) { contentSize.height = NS_MIN(aReflowState.mComputedMaxHeight, contentSize.height); } if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinHeight) { contentSize.height = NS_MAX(aReflowState.mComputedMinHeight, contentSize.height); } } if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) { contentSize.width = aReflowState.ComputedWidth(); } else { if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) { contentSize.width = NS_MIN(aReflowState.mComputedMaxWidth, contentSize.width); } if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) { contentSize.width = NS_MAX(aReflowState.mComputedMinWidth, contentSize.width); } } aDesiredSize.height = borderPadding.top + contentSize.height + borderPadding.bottom; aDesiredSize.width = contentSize.width + borderPadding.left + borderPadding.right; aDesiredSize.mOverflowAreas = overflowRects; aDesiredSize.UnionOverflowAreasWithDesiredBounds(); #ifdef DEBUG_roc printf("*** DONE PASS feasible=%d\n", allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)); #endif return allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus); }
NS_IMETHODIMP nsCanvasFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow"); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; nsCanvasFrame* prevCanvasFrame = static_cast<nsCanvasFrame*> (GetPrevInFlow()); if (prevCanvasFrame) { nsAutoPtr<nsFrameList> overflow(prevCanvasFrame->StealOverflowFrames()); if (overflow) { NS_ASSERTION(overflow->OnlyChild(), "must have doc root as canvas frame's only child"); nsContainerFrame::ReparentFrameViewList(aPresContext, *overflow, prevCanvasFrame, this); // Prepend overflow to the our child list. There may already be // children placeholders for fixed-pos elements, which don't get // reflowed but must not be lost until the canvas frame is destroyed. mFrames.InsertFrames(this, nullptr, *overflow); } } // Set our size up front, since some parts of reflow depend on it // being already set. Note that the computed height may be // unconstrained; that's ok. Consumers should watch out for that. SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); // Reflow our one and only normal child frame. It's either the root // element's frame or a placeholder for that frame, if the root element // is abs-pos or fixed-pos. We may have additional children which // are placeholders for continuations of fixed-pos content, but those // don't need to be reflowed. The normal child is always comes before // the fixed-pos placeholders, because we insert it at the start // of the child list, above. nsHTMLReflowMetrics kidDesiredSize; if (mFrames.IsEmpty()) { // We have no child frame, so return an empty size aDesiredSize.width = aDesiredSize.height = 0; } else { nsIFrame* kidFrame = mFrames.FirstChild(); bool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0; nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, nsSize(aReflowState.availableWidth, aReflowState.availableHeight)); if (aReflowState.mFlags.mVResize && (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) { // Tell our kid it's being vertically resized too. Bit of a // hack for framesets. kidReflowState.mFlags.mVResize = true; } nsPoint kidPt(kidReflowState.mComputedMargin.left, kidReflowState.mComputedMargin.top); // Apply CSS relative positioning const nsStyleDisplay* styleDisp = kidFrame->GetStyleDisplay(); if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) { kidPt += nsPoint(kidReflowState.mComputedOffsets.left, kidReflowState.mComputedOffsets.top); } // Reflow the frame ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, kidPt.x, kidPt.y, 0, aStatus); // Complete the reflow and position and size the child frame FinishReflowChild(kidFrame, aPresContext, &kidReflowState, kidDesiredSize, kidPt.x, kidPt.y, 0); if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) { nsIFrame* nextFrame = kidFrame->GetNextInFlow(); NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW, "If it's incomplete and has no nif yet, it must flag a nif reflow."); if (!nextFrame) { nsresult rv = aPresContext->PresShell()->FrameConstructor()-> CreateContinuingFrame(aPresContext, kidFrame, this, &nextFrame); NS_ENSURE_SUCCESS(rv, rv); SetOverflowFrames(aPresContext, nsFrameList(nextFrame, nextFrame)); // Root overflow containers will be normal children of // the canvas frame, but that's ok because there // aren't any other frames we need to isolate them from // during reflow. } if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); } } // If the child frame was just inserted, then we're responsible for making sure // it repaints if (kidDirty) { // But we have a new child, which will affect our background, so // invalidate our whole rect. // Note: Even though we request to be sized to our child's size, our // scroll frame ensures that we are always the size of the viewport. // Also note: GetPosition() on a CanvasFrame is always going to return // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect() // could also include overflow to our top and left (out of the viewport) // which doesn't need to be painted. nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame(); viewport->InvalidateFrame(); } // Return our desired size. Normally it's what we're told, but // sometimes we can be given an unconstrained height (when a window // is sizing-to-content), and we should compute our desired height. aDesiredSize.width = aReflowState.ComputedWidth(); if (aReflowState.ComputedHeight() == NS_UNCONSTRAINEDSIZE) { aDesiredSize.height = kidFrame->GetRect().height + kidReflowState.mComputedMargin.TopBottom(); } else { aDesiredSize.height = aReflowState.ComputedHeight(); } aDesiredSize.SetOverflowAreasToDesiredBounds(); aDesiredSize.mOverflowAreas.UnionWith( kidDesiredSize.mOverflowAreas + kidPt); } if (prevCanvasFrame) { ReflowOverflowContainerChildren(aPresContext, aReflowState, aDesiredSize.mOverflowAreas, 0, aStatus); } FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); NS_FRAME_TRACE_REFLOW_OUT("nsCanvasFrame::Reflow", aStatus); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
NS_IMETHODIMP nsFieldSetFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame", aReflowState.reason); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; // Should we create a space manager? nsAutoSpaceManager autoSpaceManager(NS_CONST_CAST(nsHTMLReflowState &, aReflowState)); // XXXldb If we start storing the space manager in the frame rather // than keeping it around only during reflow then we should create it // only when there are actually floats to manage. Otherwise things // like tables will gain significant bloat. if (NS_BLOCK_SPACE_MGR & mState) autoSpaceManager.CreateSpaceManagerFor(aPresContext, this); //------------ Handle Incremental Reflow ----------------- PRBool reflowContent = PR_TRUE; PRBool reflowLegend = PR_TRUE; nsReflowReason reason = aReflowState.reason; if (reason == eReflowReason_Incremental) { nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; // See if it's targeted at us if (command) { nsReflowType reflowType; command->GetType(reflowType); switch (reflowType) { case eReflowType_StyleChanged: reason = eReflowReason_StyleChange; break; case eReflowType_ReflowDirty: reason = eReflowReason_Dirty; break; default: NS_ERROR("Unexpected Reflow Type"); } } else { reflowContent = PR_FALSE; reflowLegend = PR_FALSE; nsReflowPath::iterator iter = aReflowState.path->FirstChild(); nsReflowPath::iterator end = aReflowState.path->EndChildren(); for ( ; iter != end; ++iter) { if (*iter == mLegendFrame) reflowLegend = PR_TRUE; else if (*iter == mContentFrame) reflowContent = PR_TRUE; } } } if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { reflowLegend = PR_TRUE; reflowContent = PR_TRUE; } else if (reason == eReflowReason_Dirty) { // if dirty then check dirty flags if (GetStateBits() & NS_FRAME_IS_DIRTY) { reflowLegend = PR_TRUE; reflowContent = PR_TRUE; } else { if (reflowContent) { reflowContent = mContentFrame ? (mContentFrame->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0 : PR_FALSE; } if (reflowLegend) { reflowLegend = mLegendFrame ? (mLegendFrame->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0 : PR_FALSE; } } } // availSize could have unconstrained values, don't perform any addition on them nsSize availSize(aReflowState.mComputedWidth, aReflowState.availableHeight); // get our border and padding const nsMargin &borderPadding = aReflowState.mComputedBorderPadding; const nsMargin &padding = aReflowState.mComputedPadding; nsMargin border = borderPadding - padding; if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = borderPadding.left + borderPadding.right; } // Figure out how big the legend is if there is one. // get the legend's margin nsMargin legendMargin(0,0,0,0); // reflow the legend only if needed if (mLegendFrame) { const nsStyleMargin* marginStyle = mLegendFrame->GetStyleMargin(); marginStyle->GetMargin(legendMargin); if (reflowLegend) { nsHTMLReflowState legendReflowState(aPresContext, aReflowState, mLegendFrame, nsSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE), reason); // always give the legend as much size as it needs legendReflowState.mComputedWidth = NS_INTRINSICSIZE; legendReflowState.mComputedHeight = NS_INTRINSICSIZE; nsHTMLReflowMetrics legendDesiredSize(0,0); ReflowChild(mLegendFrame, aPresContext, legendDesiredSize, legendReflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); #ifdef NOISY_REFLOW printf(" returned (%d, %d)\n", legendDesiredSize.width, legendDesiredSize.height); if (legendDesiredSize.mComputeMEW) printf(" and maxEW %d\n", legendDesiredSize.mMaxElementWidth); #endif // figure out the legend's rectangle mLegendRect.width = legendDesiredSize.width + legendMargin.left + legendMargin.right; mLegendRect.height = legendDesiredSize.height + legendMargin.top + legendMargin.bottom; mLegendRect.x = borderPadding.left; mLegendRect.y = 0; nscoord oldSpace = mLegendSpace; mLegendSpace = 0; if (mLegendRect.height > border.top) { // center the border on the legend mLegendSpace = mLegendRect.height - border.top; } else { mLegendRect.y = (border.top - mLegendRect.height)/2; } // if the legend space changes then we need to reflow the // content area as well. if (mLegendSpace != oldSpace) { if (reflowContent == PR_FALSE || reason == eReflowReason_Dirty) { reflowContent = PR_TRUE; reason = eReflowReason_Resize; } } // if we are contrained then remove the legend from our available height. if (NS_INTRINSICSIZE != availSize.height) { if (availSize.height >= mLegendSpace) availSize.height -= mLegendSpace; } // don't get any smaller than the legend if (NS_INTRINSICSIZE != availSize.width) { if (availSize.width < mLegendRect.width) availSize.width = mLegendRect.width; } FinishReflowChild(mLegendFrame, aPresContext, &legendReflowState, legendDesiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME); } } else { mLegendRect.Empty(); mLegendSpace = 0; } nsRect contentRect; // reflow the content frame only if needed if (mContentFrame) { if (reflowContent) { availSize.width = aReflowState.mComputedWidth; nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mContentFrame, availSize, reason); nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags); // Reflow the frame ReflowChild(mContentFrame, aPresContext, kidDesiredSize, kidReflowState, borderPadding.left + kidReflowState.mComputedMargin.left, borderPadding.top + mLegendSpace + kidReflowState.mComputedMargin.top, 0, aStatus); // set the rect. make sure we add the margin back in. contentRect.SetRect(borderPadding.left,borderPadding.top + mLegendSpace,kidDesiredSize.width ,kidDesiredSize.height); if (aReflowState.mComputedHeight != NS_INTRINSICSIZE && borderPadding.top + mLegendSpace+kidDesiredSize.height > aReflowState.mComputedHeight) { kidDesiredSize.height = aReflowState.mComputedHeight-(borderPadding.top + mLegendSpace); } FinishReflowChild(mContentFrame, aPresContext, &kidReflowState, kidDesiredSize, contentRect.x, contentRect.y, 0); if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = kidDesiredSize.mMaxElementWidth; if (eStyleUnit_Coord == aReflowState.mStylePosition->mWidth.GetUnit() && NS_INTRINSICSIZE != aReflowState.mComputedWidth) aDesiredSize.mMaxElementWidth = aReflowState.mComputedWidth; if (eStyleUnit_Percent == aReflowState.mStylePosition->mWidth.GetUnit()) aDesiredSize.mMaxElementWidth = 0; aDesiredSize.mMaxElementWidth += borderPadding.left + borderPadding.right; } if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { aDesiredSize.mMaximumWidth = kidDesiredSize.mMaximumWidth + borderPadding.left + borderPadding.right; } NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus); } else { // if we don't need to reflow just get the old size contentRect = mContentFrame->GetRect(); const nsStyleMargin* marginStyle = mContentFrame->GetStyleMargin(); nsMargin m(0,0,0,0); marginStyle->GetMargin(m); contentRect.Inflate(m); } } // use the computed width if the inner content does not fill it if (aReflowState.mComputedWidth != NS_INTRINSICSIZE && aReflowState.mComputedWidth > contentRect.width) { contentRect.width = aReflowState.mComputedWidth; } if (mLegendFrame) { // if the content rect is larger then the legend we can align the legend if (contentRect.width > mLegendRect.width) { PRInt32 align = ((nsLegendFrame*)mLegendFrame)->GetAlign(); switch(align) { case NS_STYLE_TEXT_ALIGN_RIGHT: mLegendRect.x = contentRect.width - mLegendRect.width + borderPadding.left; break; case NS_STYLE_TEXT_ALIGN_CENTER: float p2t; p2t = aPresContext->PixelsToTwips(); mLegendRect.x = NSIntPixelsToTwips((nscoord) NSToIntRound((float)(contentRect.width/2 - mLegendRect.width/2 + borderPadding.left) / p2t),p2t); break; } } else { //otherwise make place for the legend contentRect.width = mLegendRect.width; } // place the legend nsRect actualLegendRect(mLegendRect); actualLegendRect.Deflate(legendMargin); nsPoint curOrigin = mLegendFrame->GetPosition(); // only if the origin changed if ((curOrigin.x != mLegendRect.x) || (curOrigin.y != mLegendRect.y)) { mLegendFrame->SetPosition(nsPoint(actualLegendRect.x , actualLegendRect.y)); nsContainerFrame::PositionFrameView(mLegendFrame); // We need to recursively process the legend frame's // children since we're moving the frame after Reflow. nsContainerFrame::PositionChildViews(mLegendFrame); } } // Return our size and our result if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) { aDesiredSize.height = mLegendSpace + borderPadding.top + contentRect.height + borderPadding.bottom; } else { nscoord min = borderPadding.top + borderPadding.bottom + mLegendRect.height; aDesiredSize.height = aReflowState.mComputedHeight + borderPadding.top + borderPadding.bottom; if (aDesiredSize.height < min) aDesiredSize.height = min; } aDesiredSize.width = contentRect.width + borderPadding.left + borderPadding.right; aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; if (aDesiredSize.mComputeMEW) { // if the legend is wider use it if (aDesiredSize.mMaxElementWidth < mLegendRect.width + borderPadding.left + borderPadding.right) aDesiredSize.mMaxElementWidth = mLegendRect.width + borderPadding.left + borderPadding.right; } aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height); // make the mMaximumWidth large enough if the legendframe determines the size if ((aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) && mLegendFrame) { aDesiredSize.mMaximumWidth = PR_MAX(aDesiredSize.mMaximumWidth, mLegendRect.width + borderPadding.left + borderPadding.right); } if (mLegendFrame) ConsiderChildOverflow(aDesiredSize.mOverflowArea, mLegendFrame); if (mContentFrame) ConsiderChildOverflow(aDesiredSize.mOverflowArea, mContentFrame); FinishAndStoreOverflow(&aDesiredSize); Invalidate(aDesiredSize.mOverflowArea); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }