/* virtual */ void nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // All rt children have already been reflowed. All we need to do is clean up // the line layout. aStatus = NS_FRAME_COMPLETE; mozilla::WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode(); mozilla::WritingMode frameWM = aReflowState.GetWritingMode(); mozilla::LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding(); aDesiredSize.ISize(lineWM) = mISize; nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState, borderPadding, lineWM, frameWM); nscoord bsize = aDesiredSize.BSize(lineWM); if (!mLines.empty()) { // Okay to use BlockStartAscent because it has just been correctly set by // nsLayoutUtils::SetBSizeFromFontMetrics. mLines.begin()->SetLogicalAscent(aDesiredSize.BlockStartAscent()); mLines.begin()->SetBounds(aReflowState.GetWritingMode(), 0, 0, mISize, bsize, mISize); } if (mLineLayout) { mLineLayout->EndLineReflow(); mLineLayout = nullptr; } }
void nsTableCellFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); if (aReflowState.mFlags.mSpecialBSizeReflow) { FirstInFlow()->AddStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW); } // see if a special bsize reflow needs to occur due to having a pct height nsTableFrame::CheckRequestSpecialBSizeReflow(aReflowState); aStatus = NS_FRAME_COMPLETE; WritingMode wm = aReflowState.GetWritingMode(); LogicalSize availSize(wm, aReflowState.AvailableISize(), aReflowState.AvailableBSize()); LogicalMargin borderPadding = aReflowState.ComputedLogicalPadding(); LogicalMargin border = GetBorderWidth(wm); borderPadding += border; // reduce available space by insets, if we're in a constrained situation availSize.ISize(wm) -= borderPadding.IStartEnd(wm); if (NS_UNCONSTRAINEDSIZE != availSize.BSize(wm)) { availSize.BSize(wm) -= borderPadding.BStartEnd(wm); } // Try to reflow the child into the available space. It might not // fit or might need continuing. if (availSize.BSize(wm) < 0) { availSize.BSize(wm) = 1; } nsHTMLReflowMetrics kidSize(wm, aDesiredSize.mFlags); kidSize.ClearSize(); SetPriorAvailISize(aReflowState.AvailableISize()); nsIFrame* firstKid = mFrames.FirstChild(); NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame"); nsTableFrame* tableFrame = GetTableFrame(); if (aReflowState.mFlags.mSpecialBSizeReflow) { const_cast<nsHTMLReflowState&>(aReflowState). SetComputedBSize(BSize(wm) - borderPadding.BStartEnd(wm)); DISPLAY_REFLOW_CHANGE(); } else if (aPresContext->IsPaginated()) { nscoord computedUnpaginatedBSize = CalcUnpaginatedBSize(aPresContext, (nsTableCellFrame&)*this, *tableFrame, borderPadding.BStartEnd(wm)); if (computedUnpaginatedBSize > 0) { const_cast<nsHTMLReflowState&>(aReflowState).SetComputedBSize(computedUnpaginatedBSize); DISPLAY_REFLOW_CHANGE(); } } else { SetHasPctOverBSize(false); } WritingMode kidWM = firstKid->GetWritingMode(); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid, availSize.ConvertTo(kidWM, wm)); // Don't be a percent height observer if we're in the middle of // special-bsize reflow, in case we get an accidental NotifyPercentBSize() // call (which we shouldn't honor during special-bsize reflow) if (!aReflowState.mFlags.mSpecialBSizeReflow) { // mPercentBSizeObserver is for children of cells in quirks mode, // but only those than are tables in standards mode. NeedsToObserve // will determine how far this is propagated to descendants. kidReflowState.mPercentBSizeObserver = this; } // Don't propagate special bsize reflow state to our kids kidReflowState.mFlags.mSpecialBSizeReflow = false; if (aReflowState.mFlags.mSpecialBSizeReflow || FirstInFlow()->HasAnyStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) { // We need to force the kid to have mBResize set if we've had a // special reflow in the past, since the non-special reflow needs to // resize back to what it was without the special bsize reflow. kidReflowState.SetBResize(true); } nsSize containerSize = aReflowState.ComputedSizeAsContainerIfConstrained(); LogicalPoint kidOrigin(wm, borderPadding.IStart(wm), borderPadding.BStart(wm)); nsRect origRect = firstKid->GetRect(); nsRect origVisualOverflow = firstKid->GetVisualOverflowRect(); bool firstReflow = firstKid->HasAnyStateBits(NS_FRAME_FIRST_REFLOW); ReflowChild(firstKid, aPresContext, kidSize, kidReflowState, wm, kidOrigin, containerSize, 0, aStatus); if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it //XXX should paginate overflow as overflow, but not in this patch (bug 379349) NS_FRAME_SET_INCOMPLETE(aStatus); printf("Set table cell incomplete %p\n", static_cast<void*>(this)); } // XXXbz is this invalidate actually needed, really? if (HasAnyStateBits(NS_FRAME_IS_DIRTY)) { InvalidateFrameSubtree(); } #ifdef DEBUG DebugCheckChildSize(firstKid, kidSize); #endif // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode // see testcase "emptyCells.html" nsIFrame* prevInFlow = GetPrevInFlow(); bool isEmpty; if (prevInFlow) { isEmpty = static_cast<nsTableCellFrame*>(prevInFlow)->GetContentEmpty(); } else { isEmpty = !CellHasVisibleContent(kidSize.Height(), tableFrame, firstKid); } SetContentEmpty(isEmpty); // Place the child FinishReflowChild(firstKid, aPresContext, kidSize, &kidReflowState, wm, kidOrigin, containerSize, 0); nsTableFrame::InvalidateTableFrame(firstKid, origRect, origVisualOverflow, firstReflow); // first, compute the bsize which can be set w/o being restricted by // available bsize LogicalSize cellSize(wm); cellSize.BSize(wm) = kidSize.BSize(wm); if (NS_UNCONSTRAINEDSIZE != cellSize.BSize(wm)) { cellSize.BSize(wm) += borderPadding.BStartEnd(wm); } // next determine the cell's isize cellSize.ISize(wm) = kidSize.ISize(wm); // at this point, we've factored in the cell's style attributes // factor in border and padding if (NS_UNCONSTRAINEDSIZE != cellSize.ISize(wm)) { cellSize.ISize(wm) += borderPadding.IStartEnd(wm); } // set the cell's desired size and max element size aDesiredSize.SetSize(wm, cellSize); // the overflow area will be computed when BlockDirAlignChild() gets called if (aReflowState.mFlags.mSpecialBSizeReflow) { if (aDesiredSize.BSize(wm) > BSize(wm)) { // set a bit indicating that the pct bsize contents exceeded // the height that they could honor in the pass 2 reflow SetHasPctOverBSize(true); } if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableBSize()) { aDesiredSize.BSize(wm) = BSize(wm); } } // If our parent is in initial reflow, it'll handle invalidating our // entire overflow rect. if (!GetParent()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW) && nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) { InvalidateFrame(); } // remember the desired size for this reflow SetDesiredSize(aDesiredSize); // Any absolutely-positioned children will get reflowed in // nsFrame::FixupPositionedTableParts in another pass, so propagate our // dirtiness to them before our parent clears our dirty bits. PushDirtyBitToAbsoluteFrames(); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsPageContentFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsPageContentFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); aStatus = NS_FRAME_COMPLETE; // initialize out parameter if (GetPrevInFlow() && (GetStateBits() & NS_FRAME_FIRST_REFLOW)) { nsresult rv = aPresContext->PresShell()->FrameConstructor() ->ReplicateFixedFrames(this); if (NS_FAILED(rv)) { return; } } // 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. nsSize maxSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight()); SetSize(maxSize); // A PageContentFrame must always have one child: the canvas frame. // Resize our frame allowing it only to be as big as we are // XXX Pay attention to the page's border and padding... if (mFrames.NotEmpty()) { nsIFrame* frame = mFrames.FirstChild(); WritingMode wm = frame->GetWritingMode(); LogicalSize logicalSize(wm, maxSize); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, logicalSize); kidReflowState.SetComputedBSize(logicalSize.BSize(wm)); // Reflow the page content area ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, 0, 0, 0, aStatus); // The document element's background should cover the entire canvas, so // take into account the combined area and any space taken up by // absolutely positioned elements nsMargin padding(0,0,0,0); // XXXbz this screws up percentage padding (sets padding to zero // in the percentage padding case) kidReflowState.mStylePadding->GetPadding(padding); // This is for shrink-to-fit, and therefore we want to use the // scrollable overflow, since the purpose of shrink to fit is to // make the content that ought to be reachable (represented by the // scrollable overflow) fit in the page. if (frame->HasOverflowAreas()) { // The background covers the content area and padding area, so check // for children sticking outside the child frame's padding edge nscoord xmost = aDesiredSize.ScrollableOverflow().XMost(); if (xmost > aDesiredSize.Width()) { nscoord widthToFit = xmost + padding.right + kidReflowState.mStyleBorder->GetComputedBorderWidth(NS_SIDE_RIGHT); float ratio = float(maxSize.width) / widthToFit; NS_ASSERTION(ratio >= 0.0 && ratio < 1.0, "invalid shrink-to-fit ratio"); mPD->mShrinkToFitRatio = std::min(mPD->mShrinkToFitRatio, ratio); } } // Place and size the child FinishReflowChild(frame, aPresContext, aDesiredSize, &kidReflowState, 0, 0, 0); NS_ASSERTION(aPresContext->IsDynamic() || !NS_FRAME_IS_FULLY_COMPLETE(aStatus) || !frame->GetNextInFlow(), "bad child flow list"); } // Reflow our fixed frames nsReflowStatus fixedStatus = NS_FRAME_COMPLETE; ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, fixedStatus); NS_ASSERTION(NS_FRAME_IS_COMPLETE(fixedStatus), "fixed frames can be truncated, but not incomplete"); // Return our desired size WritingMode wm = aReflowState.GetWritingMode(); aDesiredSize.ISize(wm) = aReflowState.ComputedISize(); if (aReflowState.ComputedBSize() != NS_UNCONSTRAINEDSIZE) { aDesiredSize.BSize(wm) = aReflowState.ComputedBSize(); } FinishAndStoreOverflow(&aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void BRFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("BRFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); WritingMode wm = aReflowState.GetWritingMode(); LogicalSize finalSize(wm); finalSize.BSize(wm) = 0; // BR frames with block size 0 are ignored in quirks // mode by nsLineLayout::VerticalAlignFrames . // However, it's not always 0. See below. finalSize.ISize(wm) = 0; aMetrics.SetBlockStartAscent(0); // Only when the BR is operating in a line-layout situation will it // behave like a BR. Additionally, we suppress breaks from BR inside // of ruby frames. To determine if we're inside ruby, we have to rely // on the *parent's* ShouldSuppressLineBreak() method, instead of our // own, because we may have custom "display" value that makes our // ShouldSuppressLineBreak() return false. nsLineLayout* ll = aReflowState.mLineLayout; if (ll && !GetParent()->StyleContext()->ShouldSuppressLineBreak()) { // Note that the compatibility mode check excludes AlmostStandards // mode, since this is the inline box model. See bug 161691. if ( ll->LineIsEmpty() || aPresContext->CompatibilityMode() == eCompatibility_FullStandards ) { // The line is logically empty; any whitespace is trimmed away. // // If this frame is going to terminate the line we know // that nothing else will go on the line. Therefore, in this // case, we provide some height for the BR frame so that it // creates some vertical whitespace. It's necessary to use the // line-height rather than the font size because the // quirks-mode fix that doesn't apply the block's min // line-height makes this necessary to make BR cause a line // of the full line-height // We also do this in strict mode because BR should act like a // normal inline frame. That line-height is used is important // here for cases where the line-height is less than 1. RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetInflatedFontMetricsForFrame(this); if (fm) { nscoord logicalHeight = aReflowState.CalcLineHeight(); finalSize.BSize(wm) = logicalHeight; aMetrics.SetBlockStartAscent(nsLayoutUtils::GetCenteredFontBaseline( fm, logicalHeight, wm.IsLineInverted())); } else { aMetrics.SetBlockStartAscent(aMetrics.BSize(wm) = 0); } // XXX temporary until I figure out a better solution; see the // code in nsLineLayout::VerticalAlignFrames that zaps minY/maxY // if the width is zero. // XXX This also fixes bug 10036! // Warning: nsTextControlFrame::CalculateSizeStandard depends on // the following line, see bug 228752. // The code below in AddInlinePrefISize also adds 1 appunit to width finalSize.ISize(wm) = 1; } // Return our reflow status uint32_t breakType = aReflowState.mStyleDisplay->PhysicalBreakType(wm); if (NS_STYLE_CLEAR_NONE == breakType) { breakType = NS_STYLE_CLEAR_LINE; } aStatus = NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | NS_INLINE_MAKE_BREAK_TYPE(breakType); ll->SetLineEndsInBR(true); } else { aStatus = NS_FRAME_COMPLETE; } aMetrics.SetSize(wm, finalSize); aMetrics.SetOverflowAreasToDesiredBounds(); mAscent = aMetrics.BlockStartAscent(); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); }
void nsMathMLmtableOuterFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsAutoString value; // we want to return a table that is anchored according to the align attribute nsTableOuterFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); NS_ASSERTION(aDesiredSize.Height() >= 0, "illegal height for mtable"); NS_ASSERTION(aDesiredSize.Width() >= 0, "illegal width for mtable"); // see if the user has set the align attribute on the <mtable> int32_t rowIndex = 0; eAlign tableAlign = eAlign_axis; mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::align, value); if (!value.IsEmpty()) { ParseAlignAttribute(value, tableAlign, rowIndex); } // adjustments if there is a specified row from where to anchor the table // (conceptually: when there is no row of reference, picture the table as if // it is wrapped in a single big fictional row at dy = 0, this way of // doing so allows us to have a single code path for all cases). nscoord dy = 0; WritingMode wm = aDesiredSize.GetWritingMode(); nscoord blockSize = aDesiredSize.BSize(wm); nsIFrame* rowFrame = nullptr; if (rowIndex) { rowFrame = GetRowFrameAt(rowIndex); if (rowFrame) { // translate the coordinates to be relative to us and in our writing mode nsIFrame* frame = rowFrame; LogicalRect rect(wm, frame->GetRect(), aReflowState.ComputedSizeAsContainerIfConstrained()); blockSize = rect.BSize(wm); do { dy += rect.BStart(wm); frame = frame->GetParent(); } while (frame != this); } } switch (tableAlign) { case eAlign_top: aDesiredSize.SetBlockStartAscent(dy); break; case eAlign_bottom: aDesiredSize.SetBlockStartAscent(dy + blockSize); break; case eAlign_center: aDesiredSize.SetBlockStartAscent(dy + blockSize / 2); break; case eAlign_baseline: if (rowFrame) { // anchor the table on the baseline of the row of reference nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent(); if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline' aDesiredSize.SetBlockStartAscent(dy + rowAscent); break; } } // in other situations, fallback to center aDesiredSize.SetBlockStartAscent(dy + blockSize / 2); break; case eAlign_axis: default: { // XXX should instead use style data from the row of reference here ? RefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), nsLayoutUtils:: FontSizeInflationFor(this)); nscoord axisHeight; GetAxisHeight(aReflowState.rendContext->GetDrawTarget(), fm, axisHeight); if (rowFrame) { // anchor the table on the axis of the row of reference // XXX fallback to baseline because it is a hard problem // XXX need to fetch the axis of the row; would need rowalign=axis to work better nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent(); if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline' aDesiredSize.SetBlockStartAscent(dy + rowAscent); break; } } // in other situations, fallback to using half of the height aDesiredSize.SetBlockStartAscent(dy + blockSize / 2 + axisHeight); } } mReference.x = 0; mReference.y = aDesiredSize.BlockStartAscent(); // just make-up a bounding metrics mBoundingMetrics = nsBoundingMetrics(); mBoundingMetrics.ascent = aDesiredSize.BlockStartAscent(); mBoundingMetrics.descent = aDesiredSize.Height() - aDesiredSize.BlockStartAscent(); mBoundingMetrics.width = aDesiredSize.Width(); mBoundingMetrics.leftBearing = 0; mBoundingMetrics.rightBearing = aDesiredSize.Width(); aDesiredSize.mBoundingMetrics = mBoundingMetrics; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }