// Only place the selected child ... /* virtual */ nsresult nsMathMLSelectedFrame::Place(nsRenderingContext& aRenderingContext, bool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { nsIFrame* childFrame = GetSelectedFrame(); if (mInvalidMarkup) { return ReflowError(aRenderingContext, aDesiredSize); } aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); mBoundingMetrics = nsBoundingMetrics(); if (childFrame) { GetReflowAndBoundingMetricsFor(childFrame, aDesiredSize, mBoundingMetrics); if (aPlaceOrigin) { FinishReflowChild(childFrame, PresContext(), aDesiredSize, nullptr, 0, 0, 0); } mReference.x = 0; mReference.y = aDesiredSize.BlockStartAscent(); } aDesiredSize.mBoundingMetrics = mBoundingMetrics; return NS_OK; }
void nsTableColGroupFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_ASSERTION(nullptr!=mContent, "bad state -- null content for frame"); const nsStyleVisibility* groupVis = StyleVisibility(); bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible); if (collapseGroup) { GetTableFrame()->SetNeedToCollapse(true); } // for every content child that (is a column thingy and does not already have a frame) // create a frame and adjust it's style for (nsIFrame *kidFrame = mFrames.FirstChild(); kidFrame; kidFrame = kidFrame->GetNextSibling()) { // Give the child frame a chance to reflow, even though we know it'll have 0 size nsHTMLReflowMetrics kidSize(aReflowState); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, LogicalSize(kidFrame->GetWritingMode())); nsReflowStatus status; ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, 0, 0, 0, status); FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, 0, 0, 0); } aDesiredSize.ClearSize(); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
// Only reflow the selected child ... void nsMathMLSelectedFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { aStatus = NS_FRAME_COMPLETE; aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); mBoundingMetrics = nsBoundingMetrics(); nsIFrame* childFrame = GetSelectedFrame(); if (childFrame) { WritingMode wm = childFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); ReflowChild(childFrame, aPresContext, aDesiredSize, childReflowState, aStatus); SaveReflowAndBoundingMetricsFor(childFrame, aDesiredSize, aDesiredSize.mBoundingMetrics); mBoundingMetrics = aDesiredSize.mBoundingMetrics; } FinalizeReflow(*aReflowState.rendContext, aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsPlaceholderFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { #ifdef DEBUG // We should be getting reflowed before our out-of-flow. // If this is our first reflow, and our out-of-flow has already received its // first reflow (before us), complain. // XXXdholbert This "look for a previous continuation or IB-split sibling" // code could use nsLayoutUtils::GetPrevContinuationOrIBSplitSibling(), if // we ever add a function like that. (We currently have a "Next" version.) if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && !(mOutOfFlowFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // Unfortunately, this can currently happen when the placeholder is in a // later continuation or later IB-split sibling than its out-of-flow (as // is the case in some of our existing unit tests). So for now, in that // case, we'll warn instead of asserting. bool isInContinuationOrIBSplit = false; nsIFrame* ancestor = this; while ((ancestor = ancestor->GetParent())) { if (ancestor->GetPrevContinuation() || ancestor->Properties().Get(IBSplitPrevSibling())) { isInContinuationOrIBSplit = true; break; } } if (isInContinuationOrIBSplit) { NS_WARNING("Out-of-flow frame got reflowed before its placeholder"); } else { NS_ERROR("Out-of-flow frame got reflowed before its placeholder"); } } #endif DO_GLOBAL_REFLOW_COUNT("nsPlaceholderFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); aDesiredSize.ClearSize(); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsTableColFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableColFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); aDesiredSize.ClearSize(); const nsStyleVisibility* colVis = StyleVisibility(); bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible); if (collapseCol) { nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); tableFrame->SetNeedToCollapse(true); } aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsMathMLTokenFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); mPresentationData.flags &= ~NS_MATHML_ERROR; // initializations needed for empty markup like <mtag></mtag> aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); nsIFrame* childFrame = GetFirstPrincipalChild(); while (childFrame) { // ask our children to compute their bounding metrics nsHTMLReflowMetrics childDesiredSize(aReflowState.GetWritingMode(), aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); WritingMode wm = childFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, aStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); childFrame = childFrame->GetNextSibling(); } // place and size children FinalizeReflow(aReflowState.rendContext->GetDrawTarget(), aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsMathMLmrootFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); nsReflowStatus childStatus; mPresentationData.flags &= ~NS_MATHML_ERROR; aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); nsBoundingMetrics bmSqr, bmBase, bmIndex; DrawTarget* drawTarget = aReflowState.rendContext->GetDrawTarget(); ////////////////// // Reflow Children int32_t count = 0; nsIFrame* baseFrame = nullptr; nsIFrame* indexFrame = nullptr; nsHTMLReflowMetrics baseSize(aReflowState); nsHTMLReflowMetrics indexSize(aReflowState); nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { // ask our children to compute their bounding metrics nsHTMLReflowMetrics childDesiredSize(aReflowState, aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); WritingMode wm = childFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, childStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); if (0 == count) { // base baseFrame = childFrame; baseSize = childDesiredSize; bmBase = childDesiredSize.mBoundingMetrics; } else if (1 == count) { // index indexFrame = childFrame; indexSize = childDesiredSize; bmIndex = childDesiredSize.mBoundingMetrics; } count++; childFrame = childFrame->GetNextSibling(); } if (2 != count) { // report an error, encourage people to get their markups in order ReportChildCountError(); ReflowError(drawTarget, aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); // Call DidReflow() for the child frames we successfully did reflow. DidReflowChildren(mFrames.FirstChild(), childFrame); return; } //////////// // Prepare the radical symbol and the overline bar float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this); RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation); nscoord ruleThickness, leading, psi; GetRadicalParameters(fm, StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK, ruleThickness, leading, psi); // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131) char16_t one = '1'; nsBoundingMetrics bmOne = nsLayoutUtils::AppUnitBoundsOfString(&one, 1, *fm, drawTarget); if (bmOne.ascent > bmBase.ascent) psi += bmOne.ascent - bmBase.ascent; // make sure that the rule appears on on screen nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); if (ruleThickness < onePixel) { ruleThickness = onePixel; } // adjust clearance psi to get an exact number of pixels -- this // gives a nicer & uniform look on stacked radicals (bug 130282) nscoord delta = psi % onePixel; if (delta) psi += onePixel - delta; // round up // Stretch the radical symbol to the appropriate height if it is not big enough. nsBoundingMetrics contSize = bmBase; contSize.descent = bmBase.ascent + bmBase.descent + psi; contSize.ascent = ruleThickness; // height(radical) should be >= height(base) + psi + ruleThickness nsBoundingMetrics radicalSize; mSqrChar.Stretch(aPresContext, drawTarget, fontSizeInflation, NS_STRETCH_DIRECTION_VERTICAL, contSize, radicalSize, NS_STRETCH_LARGER, StyleVisibility()->mDirection); // radicalSize have changed at this point, and should match with // the bounding metrics of the char mSqrChar.GetBoundingMetrics(bmSqr); // Update the desired size for the container (like msqrt, index is not yet included) // the baseline will be that of the base. mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness; mBoundingMetrics.descent = std::max(bmBase.descent, (bmSqr.ascent + bmSqr.descent - mBoundingMetrics.ascent)); mBoundingMetrics.width = bmSqr.width + bmBase.width; mBoundingMetrics.leftBearing = bmSqr.leftBearing; mBoundingMetrics.rightBearing = bmSqr.width + std::max(bmBase.width, bmBase.rightBearing); // take also care of the rule aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading); aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + std::max(baseSize.Height() - baseSize.BlockStartAscent(), mBoundingMetrics.descent + ruleThickness); aDesiredSize.Width() = mBoundingMetrics.width; ///////////// // Re-adjust the desired size to include the index. // the index is raised by some fraction of the height // of the radical, see \mroot macro in App. B, TexBook float raiseIndexPercent = 0.6f; gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont(); if (mathFont) { raiseIndexPercent = mathFont->GetMathConstant(gfxFontEntry::RadicalDegreeBottomRaisePercent); } nscoord raiseIndexDelta = NSToCoordRound(raiseIndexPercent * (bmSqr.ascent + bmSqr.descent)); nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical - (bmSqr.ascent + bmSqr.descent) // to bottom of radical + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index nscoord indexClearance = 0; if (mBoundingMetrics.ascent < indexRaisedAscent) { indexClearance = indexRaisedAscent - mBoundingMetrics.ascent; // excess gap introduced by a tall index mBoundingMetrics.ascent = indexRaisedAscent; nscoord descent = aDesiredSize.Height() - aDesiredSize.BlockStartAscent(); aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading); aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + descent; } nscoord dxIndex, dxSqr; GetRadicalXOffsets(bmIndex.width, bmSqr.width, fm, &dxIndex, &dxSqr); mBoundingMetrics.width = dxSqr + bmSqr.width + bmBase.width; mBoundingMetrics.leftBearing = std::min(dxIndex + bmIndex.leftBearing, dxSqr + bmSqr.leftBearing); mBoundingMetrics.rightBearing = dxSqr + bmSqr.width + std::max(bmBase.width, bmBase.rightBearing); aDesiredSize.Width() = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; GatherAndStoreOverflow(&aDesiredSize); // place the index nscoord dx = dxIndex; nscoord dy = aDesiredSize.BlockStartAscent() - (indexRaisedAscent + indexSize.BlockStartAscent() - bmIndex.ascent); FinishReflowChild(indexFrame, aPresContext, indexSize, nullptr, MirrorIfRTL(aDesiredSize.Width(), indexSize.Width(), dx), dy, 0); // place the radical symbol and the radical bar dx = dxSqr; dy = indexClearance + leading; // leave a leading at the top mSqrChar.SetRect(nsRect(MirrorIfRTL(aDesiredSize.Width(), bmSqr.width, dx), dy, bmSqr.width, bmSqr.ascent + bmSqr.descent)); dx += bmSqr.width; mBarRect.SetRect(MirrorIfRTL(aDesiredSize.Width(), bmBase.width, dx), dy, bmBase.width, ruleThickness); // place the base dy = aDesiredSize.BlockStartAscent() - baseSize.BlockStartAscent(); FinishReflowChild(baseFrame, aPresContext, baseSize, nullptr, MirrorIfRTL(aDesiredSize.Width(), baseSize.Width(), dx), dy, 0); mReference.x = 0; mReference.y = aDesiredSize.BlockStartAscent(); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsMathMLmfencedFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); mPresentationData.flags &= ~NS_MATHML_ERROR; aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); int32_t i; const nsStyleFont* font = StyleFont(); float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this); RefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), fontSizeInflation); nscoord axisHeight, em; GetAxisHeight(*aReflowState.rendContext, fm, axisHeight); GetEmHeight(fm, em); // leading to be left at the top and the bottom of stretched chars nscoord leading = NSToCoordRound(0.2f * em); ///////////// // Reflow children // Asking each child to cache its bounding metrics // Note that we don't use the base method nsMathMLContainerFrame::Reflow() // because we want to stretch our fences, separators and stretchy frames using // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base // method here, our stretchy frames will be stretched and placed, and we may // end up stretching our fences/separators with a different aDesiredSize. // XXX The above decision was revisited in bug 121748 and this code can be // refactored to use nsMathMLContainerFrame::Reflow() at some stage. nsReflowStatus childStatus; nsIFrame* firstChild = GetFirstPrincipalChild(); nsIFrame* childFrame = firstChild; nscoord ascent = 0, descent = 0; if (firstChild || mOpenChar || mCloseChar || mSeparatorsCount > 0) { // We use the ASCII metrics to get our minimum height. This way, // if we have borders or a background, they will fit better with // other elements on the line. ascent = fm->MaxAscent(); descent = fm->MaxDescent(); } while (childFrame) { nsHTMLReflowMetrics childDesiredSize(aReflowState, aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); WritingMode wm = childFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, childStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); mozilla::WritingMode outerWM = aReflowState.GetWritingMode(); nscoord childDescent = childDesiredSize.BSize(outerWM) - childDesiredSize.BlockStartAscent(); if (descent < childDescent) descent = childDescent; if (ascent < childDesiredSize.BlockStartAscent()) ascent = childDesiredSize.BlockStartAscent(); childFrame = childFrame->GetNextSibling(); } ///////////// // Ask stretchy children to stretch themselves nsBoundingMetrics containerSize; nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL; GetPreferredStretchSize(*aReflowState.rendContext, 0, /* i.e., without embellishments */ stretchDir, containerSize); childFrame = firstChild; while (childFrame) { nsIMathMLFrame* mathmlChild = do_QueryFrame(childFrame); if (mathmlChild) { nsHTMLReflowMetrics childDesiredSize(aReflowState); // retrieve the metrics that was stored at the previous pass GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); mathmlChild->Stretch(*aReflowState.rendContext, stretchDir, containerSize, childDesiredSize); // store the updated metrics SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); nscoord childDescent = childDesiredSize.Height() - childDesiredSize.BlockStartAscent(); if (descent < childDescent) descent = childDescent; if (ascent < childDesiredSize.BlockStartAscent()) ascent = childDesiredSize.BlockStartAscent(); } childFrame = childFrame->GetNextSibling(); } // bug 121748: for surrounding fences & separators, use a size that covers everything GetPreferredStretchSize(*aReflowState.rendContext, STRETCH_CONSIDER_EMBELLISHMENTS, stretchDir, containerSize); bool isRTL = StyleVisibility()->mDirection; // To achieve a minimum size of "1", the container should be enlarged by the // unstretched metrics of the fences and separators. ApplyUnstretchedMetrics(aPresContext, *aReflowState.rendContext, fontSizeInflation, mOpenChar, containerSize, isRTL); for (i = 0; i < mSeparatorsCount; i++) { ApplyUnstretchedMetrics(aPresContext, *aReflowState.rendContext, fontSizeInflation, &mSeparatorsChar[i], containerSize, isRTL); } ApplyUnstretchedMetrics(aPresContext, *aReflowState.rendContext, fontSizeInflation, mCloseChar, containerSize, isRTL); ////////////////////////////////////////// // Prepare the opening fence, separators, and closing fence, and // adjust the origin of children. // we need to center around the axis nscoord delta = std::max(containerSize.ascent - axisHeight, containerSize.descent + axisHeight); containerSize.ascent = delta + axisHeight; containerSize.descent = delta - axisHeight; ///////////////// // opening fence ... ReflowChar(aPresContext, *aReflowState.rendContext, *fm, fontSizeInflation, mOpenChar, NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, axisHeight, leading, em, containerSize, ascent, descent, isRTL); ///////////////// // separators ... for (i = 0; i < mSeparatorsCount; i++) { ReflowChar(aPresContext, *aReflowState.rendContext, *fm, fontSizeInflation, &mSeparatorsChar[i], NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, axisHeight, leading, em, containerSize, ascent, descent, isRTL); } ///////////////// // closing fence ... ReflowChar(aPresContext, *aReflowState.rendContext, *fm, fontSizeInflation, mCloseChar, NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, axisHeight, leading, em, containerSize, ascent, descent, isRTL); ////////////////// // Adjust the origins of each child. // and update our bounding metrics i = 0; nscoord dx = 0; nsBoundingMetrics bm; bool firstTime = true; nsMathMLChar *leftChar, *rightChar; if (isRTL) { leftChar = mCloseChar; rightChar = mOpenChar; } else { leftChar = mOpenChar; rightChar = mCloseChar; } if (leftChar) { PlaceChar(leftChar, ascent, bm, dx); aDesiredSize.mBoundingMetrics = bm; firstTime = false; } if (isRTL) { childFrame = this->GetLastChild(nsIFrame::kPrincipalList); } else { childFrame = firstChild; } while (childFrame) { nsHTMLReflowMetrics childSize(aReflowState); GetReflowAndBoundingMetricsFor(childFrame, childSize, bm); if (firstTime) { firstTime = false; aDesiredSize.mBoundingMetrics = bm; } else aDesiredSize.mBoundingMetrics += bm; FinishReflowChild(childFrame, aPresContext, childSize, nullptr, dx, ascent - childSize.BlockStartAscent(), 0); dx += childSize.Width(); if (i < mSeparatorsCount) { PlaceChar(&mSeparatorsChar[isRTL ? mSeparatorsCount - 1 - i : i], ascent, bm, dx); aDesiredSize.mBoundingMetrics += bm; } i++; if (isRTL) { childFrame = childFrame->GetPrevSibling(); } else { childFrame = childFrame->GetNextSibling(); } } if (rightChar) { PlaceChar(rightChar, ascent, bm, dx); if (firstTime) aDesiredSize.mBoundingMetrics = bm; else aDesiredSize.mBoundingMetrics += bm; } aDesiredSize.Width() = aDesiredSize.mBoundingMetrics.width; aDesiredSize.Height() = ascent + descent; aDesiredSize.SetBlockStartAscent(ascent); SetBoundingMetrics(aDesiredSize.mBoundingMetrics); SetReference(nsPoint(0, aDesiredSize.BlockStartAscent())); // see if we should fix the spacing FixInterFrameSpacing(aDesiredSize); // Finished with these: ClearSavedChildMetrics(); // Set our overflow area GatherAndStoreOverflow(&aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsTableOuterFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aOuterRS, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame"); DISPLAY_REFLOW(aPresContext, this, aOuterRS, aDesiredSize, aStatus); uint8_t captionSide = GetCaptionSide(); // Initialize out parameters aDesiredSize.ClearSize(); aStatus = NS_FRAME_COMPLETE; if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // Set up our kids. They're already present, on an overflow list, // or there are none so we'll create them now MoveOverflowToChildList(); } // Use longs to get more-aligned space. #define LONGS_IN_HTMLRS \ ((sizeof(nsHTMLReflowState) + sizeof(long) - 1) / sizeof(long)) long captionRSSpace[LONGS_IN_HTMLRS]; nsHTMLReflowState *captionRS = static_cast<nsHTMLReflowState*>((void*)captionRSSpace); long innerRSSpace[LONGS_IN_HTMLRS]; nsHTMLReflowState *innerRS = static_cast<nsHTMLReflowState*>((void*) innerRSSpace); nsRect origInnerRect = InnerTableFrame()->GetRect(); nsRect origInnerVisualOverflow = InnerTableFrame()->GetVisualOverflowRect(); bool innerFirstReflow = (InnerTableFrame()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; nsRect origCaptionRect; nsRect origCaptionVisualOverflow; bool captionFirstReflow; if (mCaptionFrames.NotEmpty()) { origCaptionRect = mCaptionFrames.FirstChild()->GetRect(); origCaptionVisualOverflow = mCaptionFrames.FirstChild()->GetVisualOverflowRect(); captionFirstReflow = (mCaptionFrames.FirstChild()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; } // ComputeAutoSize has to match this logic. WritingMode wm; if (captionSide == NO_SIDE) { // We don't have a caption. wm = InnerTableFrame()->GetWritingMode(); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, aOuterRS.ComputedSize(wm).ISize(wm)); } else if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT || captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) { // nsTableCaptionFrame::ComputeAutoSize takes care of making side // captions small. Compute the caption's size first, and tell the // table to fit in what's left. wm = mCaptionFrames.FirstChild()->GetWritingMode(); OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS, captionRSSpace, aOuterRS.ComputedSize(wm).ISize(wm)); nscoord innerAvailISize = aOuterRS.ComputedSize(wm).ISize(wm) - captionRS->ComputedSizeWithMarginBorderPadding(wm).ISize(wm); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, innerAvailISize); } else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP || captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) { // Compute the table's size first, and then prevent the caption from // being wider unless it has to be. // // Note that CSS 2.1 (but not 2.0) says: // The width of the anonymous box is the border-edge width of the // table box inside it // We don't actually make our anonymous box that width (if we did, // it would break 'auto' margins), but this effectively does that. wm = InnerTableFrame()->GetWritingMode(); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, aOuterRS.ComputedSize(wm).ISize(wm)); // It's good that CSS 2.1 says not to include margins, since we // can't, since they already been converted so they exactly // fill the available width (ignoring the margin on one side if // neither are auto). (We take advantage of that later when we call // GetCaptionOrigin, though.) nscoord innerBorderWidth = innerRS->ComputedSizeWithBorderPadding(wm).ISize(wm); OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS, captionRSSpace, innerBorderWidth); } else { NS_ASSERTION(captionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE || captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE, "unexpected caption-side"); // Size the table and the caption independently. wm = mCaptionFrames.FirstChild()->GetWritingMode(); OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS, captionRSSpace, aOuterRS.ComputedSize(wm).ISize(wm)); wm = InnerTableFrame()->GetWritingMode(); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, aOuterRS.ComputedSize(wm).ISize(wm)); } // First reflow the caption. nsHTMLReflowMetrics captionMet(captionRS->GetWritingMode()); nsSize captionSize; nsMargin captionMargin; if (mCaptionFrames.NotEmpty()) { nsReflowStatus capStatus; // don't let the caption cause incomplete OuterDoReflowChild(aPresContext, mCaptionFrames.FirstChild(), *captionRS, captionMet, capStatus); captionSize.width = captionMet.Width(); captionSize.height = captionMet.Height(); captionMargin = captionRS->ComputedPhysicalMargin(); // Now that we know the height of the caption, reduce the available height // for the table frame if we are height constrained and the caption is above // or below the inner table. if (NS_UNCONSTRAINEDSIZE != aOuterRS.AvailableHeight()) { nscoord captionHeight = 0; switch (captionSide) { case NS_STYLE_CAPTION_SIDE_TOP: case NS_STYLE_CAPTION_SIDE_BOTTOM: case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE: case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE: { captionHeight = captionSize.height + captionMargin.TopBottom(); break; } } innerRS->AvailableHeight() = std::max(0, innerRS->AvailableHeight() - captionHeight); } } else { captionSize.SizeTo(0,0); captionMargin.SizeTo(0,0,0,0); } // Then, now that we know how much to reduce the width of the inner // table to account for side captions, reflow the inner table. nsHTMLReflowMetrics innerMet(innerRS->GetWritingMode()); OuterDoReflowChild(aPresContext, InnerTableFrame(), *innerRS, innerMet, aStatus); nsSize innerSize; innerSize.width = innerMet.Width(); innerSize.height = innerMet.Height(); nsMargin innerMargin = innerRS->ComputedPhysicalMargin(); nsSize containSize = GetContainingBlockSize(aOuterRS); // Now that we've reflowed both we can place them. // XXXldb Most of the input variables here are now uninitialized! // XXX Need to recompute inner table's auto margins for the case of side // captions. (Caption's are broken too, but that should be fixed earlier.) if (mCaptionFrames.NotEmpty()) { nsPoint captionOrigin; GetCaptionOrigin(captionSide, containSize, innerSize, innerMargin, captionSize, captionMargin, captionOrigin); FinishReflowChild(mCaptionFrames.FirstChild(), aPresContext, captionMet, captionRS, captionOrigin.x, captionOrigin.y, 0); captionRS->~nsHTMLReflowState(); } // XXX If the height is constrained then we need to check whether // everything still fits... nsPoint innerOrigin; GetInnerOrigin(captionSide, containSize, captionSize, captionMargin, innerSize, innerMargin, innerOrigin); FinishReflowChild(InnerTableFrame(), aPresContext, innerMet, innerRS, innerOrigin.x, innerOrigin.y, 0); innerRS->~nsHTMLReflowState(); nsTableFrame::InvalidateTableFrame(InnerTableFrame(), origInnerRect, origInnerVisualOverflow, innerFirstReflow); if (mCaptionFrames.NotEmpty()) { nsTableFrame::InvalidateTableFrame(mCaptionFrames.FirstChild(), origCaptionRect, origCaptionVisualOverflow, captionFirstReflow); } UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, captionMargin); if (GetPrevInFlow()) { ReflowOverflowContainerChildren(aPresContext, aOuterRS, aDesiredSize.mOverflowAreas, 0, aStatus); } FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aOuterRS, aStatus); // Return our desired rect NS_FRAME_SET_TRUNCATION(aStatus, aOuterRS, aDesiredSize); }