void nsTableWrapperFrame::OuterDoReflowChild(nsPresContext* aPresContext, nsIFrame* aChildFrame, const ReflowInput& aChildRI, ReflowOutput& aMetrics, nsReflowStatus& aStatus) { // Using zero as containerSize here because we want consistency between // the GetLogicalPosition and ReflowChild calls, to avoid unnecessarily // changing the frame's coordinates; but we don't yet know its final // position anyway so the actual value is unimportant. const nsSize zeroCSize; WritingMode wm = aChildRI.GetWritingMode(); // Use the current position as a best guess for placement. LogicalPoint childPt = aChildFrame->GetLogicalPosition(wm, zeroCSize); uint32_t flags = NS_FRAME_NO_MOVE_FRAME; // We don't want to delete our next-in-flow's child if it's an inner table // frame, because table wrapper frames always assume that their inner table // frames don't go away. If a table wrapper frame is removed because it is // a next-in-flow of an already complete table wrapper frame, then it will // take care of removing it's inner table frame. if (aChildFrame == InnerTableFrame()) { flags |= NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD; } ReflowChild(aChildFrame, aPresContext, aMetrics, aChildRI, wm, childPt, zeroCSize, flags, aStatus); }
void nsTableWrapperFrame::InitChildReflowInput(nsPresContext& aPresContext, ReflowInput& aReflowInput) { nsMargin collapseBorder; nsMargin collapsePadding(0,0,0,0); nsMargin* pCollapseBorder = nullptr; nsMargin* pCollapsePadding = nullptr; Maybe<LogicalSize> cbSize; if (aReflowInput.mFrame == InnerTableFrame()) { WritingMode wm = aReflowInput.GetWritingMode(); if (InnerTableFrame()->IsBorderCollapse()) { LogicalMargin border = InnerTableFrame()->GetIncludedOuterBCBorder(wm); collapseBorder = border.GetPhysicalMargin(wm); pCollapseBorder = &collapseBorder; pCollapsePadding = &collapsePadding; } // Propagate our stored CB size if present, minus any margins. if (!HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) { LogicalSize* cb = Properties().Get(GridItemCBSizeProperty()); if (cb) { cbSize.emplace(*cb); *cbSize -= aReflowInput.ComputedLogicalMargin().Size(wm); } } } aReflowInput.Init(&aPresContext, cbSize.ptrOr(nullptr), pCollapseBorder, pCollapsePadding); }
void nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY), "Should not have been called"); // Only InvalidateAndScheduleBoundsUpdate marks us with NS_FRAME_IS_DIRTY, // so if that bit is still set we still have a resize pending. If we hit // this assertion, then we should get the presShell to skip reflow roots // that have a dirty parent since a reflow is going to come via the // reflow root's parent anyway. NS_ASSERTION(!(GetStateBits() & NS_FRAME_IS_DIRTY), "Reflowing while a resize is pending is wasteful"); // ReflowSVG makes sure mRect is up to date before we're called. NS_ASSERTION(!aReflowInput.mParentReflowInput, "should only get reflow from being reflow root"); NS_ASSERTION(aReflowInput.ComputedWidth() == GetSize().width && aReflowInput.ComputedHeight() == GetSize().height, "reflow roots should be reflowed at existing size and " "svg.css should ensure we have no padding/border/margin"); DoReflow(); WritingMode wm = aReflowInput.GetWritingMode(); LogicalSize finalSize(wm, aReflowInput.ComputedISize(), aReflowInput.ComputedBSize()); aDesiredSize.SetSize(wm, finalSize); aDesiredSize.SetOverflowAreasToDesiredBounds(); aStatus = NS_FRAME_COMPLETE; }
// Return the inline-size that the float (including margins) will take up // in the writing mode of the containing block. If this returns // NS_UNCONSTRAINEDSIZE, we're dealing with an orthogonal block that // has block-size:auto, and we'll need to actually reflow it to find out // how much inline-size it will occupy in the containing block's mode. static nscoord FloatMarginISize(const ReflowInput& aCBReflowInput, nscoord aFloatAvailableISize, nsIFrame *aFloat, const SizeComputationInput& aFloatOffsetState) { AutoMaybeDisableFontInflation an(aFloat); WritingMode wm = aFloatOffsetState.GetWritingMode(); LogicalSize floatSize = aFloat->ComputeSize( aCBReflowInput.mRenderingContext, wm, aCBReflowInput.ComputedSize(wm), aFloatAvailableISize, aFloatOffsetState.ComputedLogicalMargin().Size(wm), aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm) - aFloatOffsetState.ComputedLogicalPadding().Size(wm), aFloatOffsetState.ComputedLogicalPadding().Size(wm), nsIFrame::ComputeSizeFlags::eShrinkWrap); WritingMode cbwm = aCBReflowInput.GetWritingMode(); nscoord floatISize = floatSize.ConvertTo(cbwm, wm).ISize(cbwm); if (floatISize == NS_UNCONSTRAINEDSIZE) { return NS_UNCONSTRAINEDSIZE; // reflow is needed to get the true size } return floatISize + aFloatOffsetState.ComputedLogicalMargin().Size(wm). ConvertTo(cbwm, wm).ISize(cbwm) + aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm). ConvertTo(cbwm, wm).ISize(cbwm); }
void nsProgressFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsProgressFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); NS_ASSERTION(mBarDiv, "Progress bar div must exist!"); NS_ASSERTION(!GetPrevContinuation(), "nsProgressFrame should not have continuations; if it does we " "need to call RegUnregAccessKey only for the first."); if (mState & NS_FRAME_FIRST_REFLOW) { nsFormControlFrame::RegUnRegAccessKey(this, true); } nsIFrame* barFrame = mBarDiv->GetPrimaryFrame(); NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!"); ReflowBarFrame(barFrame, aPresContext, aReflowInput, aStatus); aDesiredSize.SetSize(aReflowInput.GetWritingMode(), aReflowInput.ComputedSizeWithBorderPadding()); aDesiredSize.SetOverflowAreasToDesiredBounds(); ConsiderChildOverflow(aDesiredSize.mOverflowAreas, barFrame); FinishAndStoreOverflow(&aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); }
void nsTextControlFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); // make sure that the form registers itself on the initial/first reflow if (mState & NS_FRAME_FIRST_REFLOW) { nsFormControlFrame::RegUnRegAccessKey(this, true); } // set values of reflow's out parameters WritingMode wm = aReflowInput.GetWritingMode(); LogicalSize finalSize(wm, aReflowInput.ComputedISize() + aReflowInput.ComputedLogicalBorderPadding().IStartEnd(wm), aReflowInput.ComputedBSize() + aReflowInput.ComputedLogicalBorderPadding().BStartEnd(wm)); aDesiredSize.SetSize(wm, finalSize); // computation of the ascent wrt the input height nscoord lineHeight = aReflowInput.ComputedBSize(); float inflation = nsLayoutUtils::FontSizeInflationFor(this); if (!IsSingleLineTextControl()) { lineHeight = ReflowInput::CalcLineHeight(GetContent(), StyleContext(), NS_AUTOHEIGHT, inflation); } RefPtr<nsFontMetrics> fontMet = nsLayoutUtils::GetFontMetricsForFrame(this, inflation); // now adjust for our borders and padding aDesiredSize.SetBlockStartAscent( nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight, wm.IsLineInverted()) + aReflowInput.ComputedLogicalBorderPadding().BStart(wm)); // overflow handling aDesiredSize.SetOverflowAreasToDesiredBounds(); // perform reflow on all kids nsIFrame* kid = mFrames.FirstChild(); while (kid) { ReflowTextControlChild(kid, aPresContext, aReflowInput, aStatus, aDesiredSize); kid = kid->GetNextSibling(); } // take into account css properties that affect overflow handling FinishAndStoreOverflow(&aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); }
static nscoord GetAvailableContentISize(const ReflowInput& aReflowInput) { if (aReflowInput.AvailableISize() == NS_INTRINSICSIZE) { return NS_INTRINSICSIZE; } WritingMode wm = aReflowInput.GetWritingMode(); nscoord borderPaddingISize = aReflowInput.ComputedLogicalBorderPadding().IStartEnd(wm); return std::max(0, aReflowInput.AvailableISize() - borderPaddingISize); }
nscoord nsColumnSetFrame::GetAvailableContentBSize(const ReflowInput& aReflowInput) { if (aReflowInput.AvailableBSize() == NS_INTRINSICSIZE) { return NS_INTRINSICSIZE; } WritingMode wm = aReflowInput.GetWritingMode(); LogicalMargin bp = aReflowInput.ComputedLogicalBorderPadding(); bp.ApplySkipSides(GetLogicalSkipSides(&aReflowInput)); bp.BEnd(wm) = aReflowInput.ComputedLogicalBorderPadding().BEnd(wm); return std::max(0, aReflowInput.AvailableBSize() - bp.BStartEnd(wm)); }
void nsTableWrapperFrame::InitChildReflowInput(nsPresContext& aPresContext, ReflowInput& aReflowInput) { nsMargin collapseBorder; nsMargin collapsePadding(0,0,0,0); nsMargin* pCollapseBorder = nullptr; nsMargin* pCollapsePadding = nullptr; if (aReflowInput.mFrame == InnerTableFrame() && InnerTableFrame()->IsBorderCollapse()) { WritingMode wm = aReflowInput.GetWritingMode(); LogicalMargin border = InnerTableFrame()->GetIncludedOuterBCBorder(wm); collapseBorder = border.GetPhysicalMargin(wm); pCollapseBorder = &collapseBorder; pCollapsePadding = &collapsePadding; } aReflowInput.Init(&aPresContext, nullptr, pCollapseBorder, pCollapsePadding); }
nscoord nsSplittableFrame::GetEffectiveComputedBSize(const ReflowInput& aReflowInput, nscoord aConsumedBSize) const { nscoord bSize = aReflowInput.ComputedBSize(); if (bSize == NS_INTRINSICSIZE) { return NS_INTRINSICSIZE; } if (aConsumedBSize == NS_INTRINSICSIZE) { aConsumedBSize = ConsumedBSize(aReflowInput.GetWritingMode()); } bSize -= aConsumedBSize; // We may have stretched the frame beyond its computed height. Oh well. return std::max(0, bSize); }
/* virtual */ void nsBackdropFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsBackdropFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); // Note that this frame is a child of the viewport frame. WritingMode wm = aReflowInput.GetWritingMode(); LogicalMargin borderPadding = aReflowInput.ComputedLogicalBorderPadding(); nscoord isize = aReflowInput.ComputedISize() + borderPadding.IStartEnd(wm); nscoord bsize = aReflowInput.ComputedBSize() + borderPadding.BStartEnd(wm); aDesiredSize.SetSize(wm, LogicalSize(wm, isize, bsize)); aStatus = NS_FRAME_COMPLETE; }
void nsSimplePageSequenceFrame::SetDesiredSize(ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nscoord aWidth, nscoord aHeight) { // Aim to fill the whole size of the document, not only so we // can act as a background in print preview but also handle overflow // in child page frames correctly. // Use availableISize so we don't cause a needless horizontal scrollbar. WritingMode wm = aReflowInput.GetWritingMode(); nscoord scaledWidth = aWidth * PresContext()->GetPrintPreviewScale(); nscoord scaledHeight = aHeight * PresContext()->GetPrintPreviewScale(); nscoord scaledISize = (wm.IsVertical() ? scaledHeight : scaledWidth); nscoord scaledBSize = (wm.IsVertical() ? scaledWidth : scaledHeight); aDesiredSize.ISize(wm) = std::max(scaledISize, aReflowInput.AvailableISize()); aDesiredSize.BSize(wm) = std::max(scaledBSize, aReflowInput.ComputedBSize()); }
// Helper-function that lets us clone the button's reflow state, but with its // ComputedWidth and ComputedHeight reduced by the amount of renderer-specific // focus border and padding that we're using. (This lets us provide a more // appropriate content-box size for descendents' percent sizes to resolve // against.) static ReflowInput CloneReflowInputWithReducedContentBox( const ReflowInput& aButtonReflowInput, const LogicalMargin& aFocusPadding) { auto wm = aButtonReflowInput.GetWritingMode(); nscoord adjustedISize = aButtonReflowInput.ComputedISize(); adjustedISize -= aFocusPadding.IStartEnd(wm); adjustedISize = std::max(0, adjustedISize); // (Only adjust the block-size if it's an actual length.) nscoord adjustedBSize = aButtonReflowInput.ComputedBSize(); if (adjustedBSize != NS_INTRINSICSIZE) { adjustedBSize -= aFocusPadding.BStartEnd(wm); adjustedBSize = std::max(0, adjustedBSize); } ReflowInput clone(aButtonReflowInput); clone.SetComputedISize(adjustedISize); clone.SetComputedBSize(adjustedBSize); return clone; }
// get the margin and padding data. ReflowInput doesn't handle the // case of auto margins void nsTableWrapperFrame::GetChildMargin(nsPresContext* aPresContext, const ReflowInput& aOuterRI, nsIFrame* aChildFrame, nscoord aAvailISize, LogicalMargin& aMargin) { NS_ASSERTION(!aChildFrame->IsTableCaption(), "didn't expect caption frame; writing-mode may be wrong!"); // construct a reflow state to compute margin and padding. Auto margins // will not be computed at this time. // create and init the child reflow state // XXX We really shouldn't construct a reflow state to do this. WritingMode wm = aOuterRI.GetWritingMode(); LogicalSize availSize(wm, aAvailISize, aOuterRI.AvailableSize(wm).BSize(wm)); ReflowInput childRI(aPresContext, aOuterRI, aChildFrame, availSize, nullptr, ReflowInput::CALLER_WILL_INIT); InitChildReflowInput(*aPresContext, childRI); aMargin = childRI.ComputedLogicalMargin(); }
/** * This function returns the offset of an abs/fixed-pos child's static * position, with respect to the "start" corner of its alignment container, * according to CSS Box Alignment. This function only operates in a single * axis at a time -- callers can choose which axis via the |aAbsPosCBAxis| * parameter. * * @param aKidReflowInput The ReflowInput for the to-be-aligned abspos child. * @param aKidSizeInAbsPosCBWM The child frame's size (after it's been given * the opportunity to reflow), in terms of the * containing block's WritingMode. * @param aPlaceholderContainer The parent of the child frame's corresponding * placeholder frame, cast to a nsContainerFrame. * (This will help us choose which alignment enum * we should use for the child.) * @param aAbsPosCBWM The child frame's containing block's WritingMode. * @param aAbsPosCBAxis The axis (of the containing block) that we should * be doing this computation for. */ static nscoord OffsetToAlignedStaticPos(const ReflowInput& aKidReflowInput, const LogicalSize& aKidSizeInAbsPosCBWM, nsContainerFrame* aPlaceholderContainer, WritingMode aAbsPosCBWM, LogicalAxis aAbsPosCBAxis) { if (!aPlaceholderContainer) { // (The placeholder container should be the thing that kicks this whole // process off, by setting PLACEHOLDER_STATICPOS_NEEDS_CSSALIGN. So it // should exist... but bail gracefully if it doesn't.) NS_ERROR("Missing placeholder-container when computing a " "CSS Box Alignment static position"); return 0; } // (Most of this function is simply preparing args that we'll pass to // AlignJustifySelf at the end.) // NOTE: Our alignment container is aPlaceholderContainer's content-box // (or an area within it, if aPlaceholderContainer is a grid). So, we'll // perform most of our arithmetic/alignment in aPlaceholderContainer's // WritingMode. For brevity, we use the abbreviation "pc" for "placeholder // container" in variables below. WritingMode pcWM = aPlaceholderContainer->GetWritingMode(); // Find what axis aAbsPosCBAxis corresponds to, in placeholder's parent's // writing-mode. LogicalAxis pcAxis = (pcWM.IsOrthogonalTo(aAbsPosCBWM) ? GetOrthogonalAxis(aAbsPosCBAxis) : aAbsPosCBAxis); nsIAtom* parentType = aPlaceholderContainer->GetType(); LogicalSize alignAreaSize(pcWM); if (parentType == nsGkAtoms::flexContainerFrame) { alignAreaSize = aPlaceholderContainer->GetLogicalSize(pcWM); LogicalMargin pcBorderPadding = aPlaceholderContainer->GetLogicalUsedBorderAndPadding(pcWM); alignAreaSize -= pcBorderPadding.Size(pcWM); } else { NS_ERROR("Unsupported container for abpsos CSS Box Alignment"); return 0; // (leave the child at the start of its alignment container) } nscoord alignAreaSizeInAxis = (pcAxis == eLogicalAxisInline) ? alignAreaSize.ISize(pcWM) : alignAreaSize.BSize(pcWM); AlignJustifyFlags flags = AlignJustifyFlags::eIgnoreAutoMargins; uint16_t alignConst = aPlaceholderContainer->CSSAlignmentForAbsPosChild(aKidReflowInput, pcAxis); // XXXdholbert: Handle <overflow-position> in bug 1311892 (by conditionally // setting AlignJustifyFlags::eOverflowSafe in |flags|.) For now, we behave // as if "unsafe" was the specified value (which is basically equivalent to // the default behavior, when no value is specified -- though the default // behavior also has some [at-risk] extra nuance about scroll containers...) // For now we ignore & strip off <overflow-position> bits, until bug 1311892. alignConst &= ~NS_STYLE_ALIGN_FLAG_BITS; // Find out if placeholder-container & the OOF child have the same start-sides // in the placeholder-container's pcAxis. WritingMode kidWM = aKidReflowInput.GetWritingMode(); if (pcWM.ParallelAxisStartsOnSameSide(pcAxis, kidWM)) { flags |= AlignJustifyFlags::eSameSide; } // (baselineAdjust is unused. CSSAlignmentForAbsPosChild() should've // converted 'baseline'/'last baseline' enums to their fallback values.) const nscoord baselineAdjust = nscoord(0); // AlignJustifySelf operates in the kid's writing mode, so we need to // represent the child's size and the desired axis in that writing mode: LogicalSize kidSizeInOwnWM = aKidSizeInAbsPosCBWM.ConvertTo(kidWM, aAbsPosCBWM); LogicalAxis kidAxis = (kidWM.IsOrthogonalTo(aAbsPosCBWM) ? GetOrthogonalAxis(aAbsPosCBAxis) : aAbsPosCBAxis); nscoord offset = CSSAlignUtils::AlignJustifySelf(alignConst, kidAxis, flags, baselineAdjust, alignAreaSizeInAxis, aKidReflowInput, kidSizeInOwnWM); // "offset" is in terms of the CSS Box Alignment container (i.e. it's in // terms of pcWM). But our return value needs to in terms of the containing // block's writing mode, which might have the opposite directionality in the // given axis. In that case, we just need to negate "offset" when returning, // to make it have the right effect as an offset for coordinates in the // containing block's writing mode. if (!pcWM.ParallelAxisStartsOnSameSide(pcAxis, aAbsPosCBWM)) { return -offset; } return offset; }
void nsTableCellFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); if (aReflowInput.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(aReflowInput); aStatus = NS_FRAME_COMPLETE; WritingMode wm = aReflowInput.GetWritingMode(); LogicalSize availSize(wm, aReflowInput.AvailableISize(), aReflowInput.AvailableBSize()); LogicalMargin borderPadding = aReflowInput.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; } ReflowOutput kidSize(wm, aDesiredSize.mFlags); kidSize.ClearSize(); SetPriorAvailISize(aReflowInput.AvailableISize()); nsIFrame* firstKid = mFrames.FirstChild(); NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame"); nsTableFrame* tableFrame = GetTableFrame(); if (aReflowInput.mFlags.mSpecialBSizeReflow) { const_cast<ReflowInput&>(aReflowInput). SetComputedBSize(BSize(wm) - borderPadding.BStartEnd(wm)); DISPLAY_REFLOW_CHANGE(); } else if (aPresContext->IsPaginated()) { nscoord computedUnpaginatedBSize = CalcUnpaginatedBSize((nsTableCellFrame&)*this, *tableFrame, borderPadding.BStartEnd(wm)); if (computedUnpaginatedBSize > 0) { const_cast<ReflowInput&>(aReflowInput).SetComputedBSize(computedUnpaginatedBSize); DISPLAY_REFLOW_CHANGE(); } } else { SetHasPctOverBSize(false); } WritingMode kidWM = firstKid->GetWritingMode(); ReflowInput kidReflowInput(aPresContext, aReflowInput, 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 (!aReflowInput.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. kidReflowInput.mPercentBSizeObserver = this; } // Don't propagate special bsize reflow state to our kids kidReflowInput.mFlags.mSpecialBSizeReflow = false; if (aReflowInput.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. kidReflowInput.SetBResize(true); } nsSize containerSize = aReflowInput.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, kidReflowInput, 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, &kidReflowInput, 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 (aReflowInput.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 == aReflowInput.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, aReflowInput, aDesiredSize); }
void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d", aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight())); NS_ASSERTION(aReflowInput.ComputedWidth() != NS_UNCONSTRAINEDSIZE, "Shouldn't have unconstrained stuff here " "thanks to the rules of reflow"); NS_ASSERTION(NS_INTRINSICSIZE != aReflowInput.ComputedHeight(), "Shouldn't have unconstrained stuff here " "thanks to ComputeAutoSize"); aStatus = NS_FRAME_COMPLETE; NS_ASSERTION(mContent->GetPrimaryFrame() == this, "Shouldn't happen"); // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed> aDesiredSize.SetSize(aReflowInput.GetWritingMode(), aReflowInput.ComputedSizeWithBorderPadding()); // "offset" is the offset of our content area from our frame's // top-left corner. nsPoint offset = nsPoint(aReflowInput.ComputedPhysicalBorderPadding().left, aReflowInput.ComputedPhysicalBorderPadding().top); if (mInnerView) { const nsMargin& bp = aReflowInput.ComputedPhysicalBorderPadding(); nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(), aDesiredSize.Height() - bp.TopBottom()); // Size & position the view according to 'object-fit' & 'object-position'. nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame(); IntrinsicSize intrinsSize; nsSize intrinsRatio; if (subDocRoot) { intrinsSize = subDocRoot->GetIntrinsicSize(); intrinsRatio = subDocRoot->GetIntrinsicRatio(); } nsRect destRect = nsLayoutUtils::ComputeObjectDestRect(nsRect(offset, innerSize), intrinsSize, intrinsRatio, StylePosition()); nsViewManager* vm = mInnerView->GetViewManager(); vm->MoveViewTo(mInnerView, destRect.x, destRect.y); vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()), true); } aDesiredSize.SetOverflowAreasToDesiredBounds(); if (!ShouldClipSubdocument()) { nsIFrame* subdocRootFrame = GetSubdocumentRootFrame(); if (subdocRootFrame) { aDesiredSize.mOverflowAreas.UnionWith(subdocRootFrame->GetOverflowAreas() + offset); } } FinishAndStoreOverflow(&aDesiredSize); if (!aPresContext->IsPaginated() && !mPostedReflowCallback) { PresContext()->PresShell()->PostReflowCallback(this); mPostedReflowCallback = true; } NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x", aDesiredSize.Width(), aDesiredSize.Height(), aStatus)); NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); }
void BRFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("BRFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus); WritingMode wm = aReflowInput.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 = aReflowInput.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 = aReflowInput.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 = aReflowInput.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, aReflowInput, aMetrics); }
void nsFirstLetterFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, const ReflowInput& aReflowInput, nsReflowStatus& aReflowStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsFirstLetterFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aReflowStatus); // Grab overflow list DrainOverflowFrames(aPresContext); nsIFrame* kid = mFrames.FirstChild(); // Setup reflow state for our child WritingMode wm = aReflowInput.GetWritingMode(); LogicalSize availSize = aReflowInput.AvailableSize(); const LogicalMargin& bp = aReflowInput.ComputedLogicalBorderPadding(); NS_ASSERTION(availSize.ISize(wm) != NS_UNCONSTRAINEDSIZE, "should no longer use unconstrained inline size"); availSize.ISize(wm) -= bp.IStartEnd(wm); if (NS_UNCONSTRAINEDSIZE != availSize.BSize(wm)) { availSize.BSize(wm) -= bp.BStartEnd(wm); } WritingMode lineWM = aMetrics.GetWritingMode(); ReflowOutput kidMetrics(lineWM); // Reflow the child if (!aReflowInput.mLineLayout) { // When there is no lineLayout provided, we provide our own. The // only time that the first-letter-frame is not reflowing in a // line context is when its floating. WritingMode kidWritingMode = WritingModeForLine(wm, kid); LogicalSize kidAvailSize = availSize.ConvertTo(kidWritingMode, wm); ReflowInput rs(aPresContext, aReflowInput, kid, kidAvailSize); nsLineLayout ll(aPresContext, nullptr, &aReflowInput, nullptr, nullptr); ll.BeginLineReflow(bp.IStart(wm), bp.BStart(wm), availSize.ISize(wm), NS_UNCONSTRAINEDSIZE, false, true, kidWritingMode, nsSize(aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight())); rs.mLineLayout = ≪ ll.SetInFirstLetter(true); ll.SetFirstLetterStyleOK(true); kid->Reflow(aPresContext, kidMetrics, rs, aReflowStatus); ll.EndLineReflow(); ll.SetInFirstLetter(false); // In the floating first-letter case, we need to set this ourselves; // nsLineLayout::BeginSpan will set it in the other case mBaseline = kidMetrics.BlockStartAscent(); // Place and size the child and update the output metrics LogicalSize convertedSize = kidMetrics.Size(lineWM).ConvertTo(wm, lineWM); kid->SetRect(nsRect(bp.IStart(wm), bp.BStart(wm), convertedSize.ISize(wm), convertedSize.BSize(wm))); kid->FinishAndStoreOverflow(&kidMetrics); kid->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED); convertedSize.ISize(wm) += bp.IStartEnd(wm); convertedSize.BSize(wm) += bp.BStartEnd(wm); aMetrics.SetSize(wm, convertedSize); aMetrics.SetBlockStartAscent(kidMetrics.BlockStartAscent() + bp.BStart(wm)); // Ensure that the overflow rect contains the child textframe's // overflow rect. // Note that if this is floating, the overline/underline drawable // area is in the overflow rect of the child textframe. aMetrics.UnionOverflowAreasWithDesiredBounds(); ConsiderChildOverflow(aMetrics.mOverflowAreas, kid); FinishAndStoreOverflow(&aMetrics); } else { // Pretend we are a span and reflow the child frame nsLineLayout* ll = aReflowInput.mLineLayout; bool pushedFrame; ll->SetInFirstLetter( mStyleContext->GetPseudo() == nsCSSPseudoElements::firstLetter); ll->BeginSpan(this, &aReflowInput, bp.IStart(wm), availSize.ISize(wm), &mBaseline); ll->ReflowFrame(kid, aReflowStatus, &kidMetrics, pushedFrame); NS_ASSERTION(lineWM.IsVertical() == wm.IsVertical(), "we're assuming we can mix sizes between lineWM and wm " "since we shouldn't have orthogonal writing modes within " "a line."); aMetrics.ISize(lineWM) = ll->EndSpan(this) + bp.IStartEnd(wm); ll->SetInFirstLetter(false); if (mStyleContext->StyleTextReset()->mInitialLetterSize != 0.0f) { aMetrics.SetBlockStartAscent(kidMetrics.BlockStartAscent() + bp.BStart(wm)); aMetrics.BSize(lineWM) = kidMetrics.BSize(lineWM) + bp.BStartEnd(wm); } else { nsLayoutUtils::SetBSizeFromFontMetrics(this, aMetrics, bp, lineWM, wm); } } if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) { // Create a continuation or remove existing continuations based on // the reflow completion status. if (NS_FRAME_IS_COMPLETE(aReflowStatus)) { if (aReflowInput.mLineLayout) { aReflowInput.mLineLayout->SetFirstLetterStyleOK(false); } nsIFrame* kidNextInFlow = kid->GetNextInFlow(); if (kidNextInFlow) { // Remove all of the childs next-in-flows kidNextInFlow->GetParent()->DeleteNextInFlowChild(kidNextInFlow, true); } } else { // Create a continuation for the child frame if it doesn't already // have one. if (!IsFloating()) { CreateNextInFlow(kid); // And then push it to our overflow list const nsFrameList& overflow = mFrames.RemoveFramesAfter(kid); if (overflow.NotEmpty()) { SetOverflowFrames(overflow); } } else if (!kid->GetNextInFlow()) { // For floating first letter frames (if a continuation wasn't already // created for us) we need to put the continuation with the rest of the // text that the first letter frame was made out of. nsIFrame* continuation; CreateContinuationForFloatingParent(aPresContext, kid, &continuation, true); } } } NS_FRAME_SET_TRUNCATION(aReflowStatus, aReflowInput, aMetrics); }
void nsNumberControlFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsNumberControlFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); NS_ASSERTION(mOuterWrapper, "Outer wrapper div must exist!"); NS_ASSERTION(!GetPrevContinuation() && !GetNextContinuation(), "nsNumberControlFrame should not have continuations; if it does we " "need to call RegUnregAccessKey only for the first"); NS_ASSERTION(!mFrames.FirstChild() || !mFrames.FirstChild()->GetNextSibling(), "We expect at most one direct child frame"); if (mState & NS_FRAME_FIRST_REFLOW) { nsFormControlFrame::RegUnRegAccessKey(this, true); } const WritingMode myWM = aReflowInput.GetWritingMode(); // The ISize of our content box, which is the available ISize // for our anonymous content: const nscoord contentBoxISize = aReflowInput.ComputedISize(); nscoord contentBoxBSize = aReflowInput.ComputedBSize(); // Figure out our border-box sizes as well (by adding borderPadding to // content-box sizes): const nscoord borderBoxISize = contentBoxISize + aReflowInput.ComputedLogicalBorderPadding().IStartEnd(myWM); nscoord borderBoxBSize; if (contentBoxBSize != NS_INTRINSICSIZE) { borderBoxBSize = contentBoxBSize + aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM); } // else, we'll figure out borderBoxBSize after we resolve contentBoxBSize. nsIFrame* outerWrapperFrame = mOuterWrapper->GetPrimaryFrame(); if (!outerWrapperFrame) { // display:none? if (contentBoxBSize == NS_INTRINSICSIZE) { contentBoxBSize = 0; borderBoxBSize = aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM); } } else { NS_ASSERTION(outerWrapperFrame == mFrames.FirstChild(), "huh?"); ReflowOutput wrappersDesiredSize(aReflowInput); WritingMode wrapperWM = outerWrapperFrame->GetWritingMode(); LogicalSize availSize = aReflowInput.ComputedSize(wrapperWM); availSize.BSize(wrapperWM) = NS_UNCONSTRAINEDSIZE; ReflowInput wrapperReflowInput(aPresContext, aReflowInput, outerWrapperFrame, availSize); // Convert wrapper margin into my own writing-mode (in case it differs): LogicalMargin wrapperMargin = wrapperReflowInput.ComputedLogicalMargin().ConvertTo(myWM, wrapperWM); // offsets of wrapper frame within this frame: LogicalPoint wrapperOffset(myWM, aReflowInput.ComputedLogicalBorderPadding().IStart(myWM) + wrapperMargin.IStart(myWM), aReflowInput.ComputedLogicalBorderPadding().BStart(myWM) + wrapperMargin.BStart(myWM)); nsReflowStatus childStatus; // We initially reflow the child with a dummy containerSize; positioning // will be fixed later. const nsSize dummyContainerSize; ReflowChild(outerWrapperFrame, aPresContext, wrappersDesiredSize, wrapperReflowInput, myWM, wrapperOffset, dummyContainerSize, 0, childStatus); MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(childStatus), "We gave our child unconstrained available block-size, " "so it should be complete"); nscoord wrappersMarginBoxBSize = wrappersDesiredSize.BSize(myWM) + wrapperMargin.BStartEnd(myWM); if (contentBoxBSize == NS_INTRINSICSIZE) { // We are intrinsically sized -- we should shrinkwrap the outer wrapper's // block-size: contentBoxBSize = wrappersMarginBoxBSize; // Make sure we obey min/max-bsize in the case when we're doing intrinsic // sizing (we get it for free when we have a non-intrinsic // aReflowInput.ComputedBSize()). Note that we do this before // adjusting for borderpadding, since ComputedMaxBSize and // ComputedMinBSize are content heights. contentBoxBSize = NS_CSS_MINMAX(contentBoxBSize, aReflowInput.ComputedMinBSize(), aReflowInput.ComputedMaxBSize()); borderBoxBSize = contentBoxBSize + aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM); } // Center child in block axis nscoord extraSpace = contentBoxBSize - wrappersMarginBoxBSize; wrapperOffset.B(myWM) += std::max(0, extraSpace / 2); // Needed in FinishReflowChild, for logical-to-physical conversion: nsSize borderBoxSize = LogicalSize(myWM, borderBoxISize, borderBoxBSize). GetPhysicalSize(myWM); // Place the child FinishReflowChild(outerWrapperFrame, aPresContext, wrappersDesiredSize, &wrapperReflowInput, myWM, wrapperOffset, borderBoxSize, 0); nsSize contentBoxSize = LogicalSize(myWM, contentBoxISize, contentBoxBSize). GetPhysicalSize(myWM); aDesiredSize.SetBlockStartAscent( wrappersDesiredSize.BlockStartAscent() + outerWrapperFrame->BStart(aReflowInput.GetWritingMode(), contentBoxSize)); } LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize); aDesiredSize.SetSize(myWM, logicalDesiredSize); aDesiredSize.SetOverflowAreasToDesiredBounds(); if (outerWrapperFrame) { ConsiderChildOverflow(aDesiredSize.mOverflowAreas, outerWrapperFrame); } FinishAndStoreOverflow(&aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); }
void nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext, ReflowOutput& aButtonDesiredSize, const ReflowInput& aButtonReflowInput, nsIFrame* aFirstKid) { WritingMode wm = GetWritingMode(); LogicalSize availSize = aButtonReflowInput.ComputedSize(wm); availSize.BSize(wm) = NS_INTRINSICSIZE; // Buttons have some bonus renderer-determined border/padding, // which occupies part of the button's content-box area: LogicalMargin focusPadding = LogicalMargin(wm, mRenderer.GetAddedButtonBorderAndPadding()); // See whether out availSize's inline-size is big enough. If it's // smaller than our intrinsic min iSize, that means that the kid // wouldn't really fit. In that case, we overflow into our internal // focuspadding (which other browsers don't have) so that there's a // little more space for it. // Note that GetMinISize includes the focusPadding. nscoord IOverflow = GetMinISize(aButtonReflowInput.mRenderingContext) - aButtonReflowInput.ComputedISize(); nscoord IFocusPadding = focusPadding.IStartEnd(wm); nscoord focusPaddingReduction = std::min(IFocusPadding, std::max(IOverflow, 0)); if (focusPaddingReduction > 0) { nscoord startReduction = focusPadding.IStart(wm); if (focusPaddingReduction != IFocusPadding) { startReduction = NSToCoordRound(startReduction * (float(focusPaddingReduction) / float(IFocusPadding))); } focusPadding.IStart(wm) -= startReduction; focusPadding.IEnd(wm) -= focusPaddingReduction - startReduction; } // shorthand for a value we need to use in a bunch of places const LogicalMargin& clbp = aButtonReflowInput.ComputedLogicalBorderPadding(); // Indent the child inside us by the focus border. We must do this separate // from the regular border. availSize.ISize(wm) -= focusPadding.IStartEnd(wm); LogicalPoint childPos(wm); childPos.I(wm) = focusPadding.IStart(wm) + clbp.IStart(wm); availSize.ISize(wm) = std::max(availSize.ISize(wm), 0); // Give child a clone of the button's reflow state, with height/width reduced // by focusPadding, so that descendants with height:100% don't protrude. ReflowInput adjustedButtonReflowInput = CloneReflowInputWithReducedContentBox(aButtonReflowInput, focusPadding); ReflowInput contentsReflowInput(aPresContext, adjustedButtonReflowInput, aFirstKid, availSize); nsReflowStatus contentsReflowStatus; ReflowOutput contentsDesiredSize(aButtonReflowInput); childPos.B(wm) = 0; // This will be set properly later, after reflowing the // child to determine its size. // We just pass a dummy containerSize here, as the child will be // repositioned later by FinishReflowChild. nsSize dummyContainerSize; ReflowChild(aFirstKid, aPresContext, contentsDesiredSize, contentsReflowInput, wm, childPos, dummyContainerSize, 0, contentsReflowStatus); MOZ_ASSERT(NS_FRAME_IS_COMPLETE(contentsReflowStatus), "We gave button-contents frame unconstrained available height, " "so it should be complete"); // Compute the button's content-box size: LogicalSize buttonContentBox(wm); if (aButtonReflowInput.ComputedBSize() != NS_INTRINSICSIZE) { // Button has a fixed block-size -- that's its content-box bSize. buttonContentBox.BSize(wm) = aButtonReflowInput.ComputedBSize(); } else { // Button is intrinsically sized -- it should shrinkwrap the // button-contents' bSize, plus any focus-padding space: buttonContentBox.BSize(wm) = contentsDesiredSize.BSize(wm) + focusPadding.BStartEnd(wm); // Make sure we obey min/max-bSize in the case when we're doing intrinsic // sizing (we get it for free when we have a non-intrinsic // aButtonReflowInput.ComputedBSize()). Note that we do this before // adjusting for borderpadding, since mComputedMaxBSize and // mComputedMinBSize are content bSizes. buttonContentBox.BSize(wm) = NS_CSS_MINMAX(buttonContentBox.BSize(wm), aButtonReflowInput.ComputedMinBSize(), aButtonReflowInput.ComputedMaxBSize()); } if (aButtonReflowInput.ComputedISize() != NS_INTRINSICSIZE) { buttonContentBox.ISize(wm) = aButtonReflowInput.ComputedISize(); } else { buttonContentBox.ISize(wm) = contentsDesiredSize.ISize(wm) + focusPadding.IStartEnd(wm); buttonContentBox.ISize(wm) = NS_CSS_MINMAX(buttonContentBox.ISize(wm), aButtonReflowInput.ComputedMinISize(), aButtonReflowInput.ComputedMaxISize()); } // Center child in the block-direction in the button // (technically, inside of the button's focus-padding area) nscoord extraSpace = buttonContentBox.BSize(wm) - focusPadding.BStartEnd(wm) - contentsDesiredSize.BSize(wm); childPos.B(wm) = std::max(0, extraSpace / 2); // Adjust childPos.B() to be in terms of the button's frame-rect, instead of // its focus-padding rect: childPos.B(wm) += focusPadding.BStart(wm) + clbp.BStart(wm); nsSize containerSize = (buttonContentBox + clbp.Size(wm)).GetPhysicalSize(wm); // Place the child FinishReflowChild(aFirstKid, aPresContext, contentsDesiredSize, &contentsReflowInput, wm, childPos, containerSize, 0); // Make sure we have a useful 'ascent' value for the child if (contentsDesiredSize.BlockStartAscent() == ReflowOutput::ASK_FOR_BASELINE) { WritingMode wm = aButtonReflowInput.GetWritingMode(); contentsDesiredSize.SetBlockStartAscent(aFirstKid->GetLogicalBaseline(wm)); } // OK, we're done with the child frame. // Use what we learned to populate the button frame's reflow metrics. // * Button's height & width are content-box size + border-box contribution: aButtonDesiredSize.SetSize(wm, LogicalSize(wm, aButtonReflowInput.ComputedISize() + clbp.IStartEnd(wm), buttonContentBox.BSize(wm) + clbp.BStartEnd(wm))); // * Button's ascent is its child's ascent, plus the child's block-offset // within our frame... unless it's orthogonal, in which case we'll use the // contents inline-size as an approximation for now. // XXX is there a better strategy? should we include border-padding? if (aButtonDesiredSize.GetWritingMode().IsOrthogonalTo(wm)) { aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.ISize(wm)); } else { aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.BlockStartAscent() + childPos.B(wm)); } aButtonDesiredSize.SetOverflowAreasToDesiredBounds(); }
void nsTableWrapperFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aOuterRI, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTableWrapperFrame"); DISPLAY_REFLOW(aPresContext, this, aOuterRI, aDesiredSize, aStatus); // Initialize out parameters aDesiredSize.ClearSize(); aStatus = NS_FRAME_COMPLETE; if (!HasAnyStateBits(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(); } Maybe<ReflowInput> captionRI; Maybe<ReflowInput> innerRI; nsRect origInnerRect = InnerTableFrame()->GetRect(); nsRect origInnerVisualOverflow = InnerTableFrame()->GetVisualOverflowRect(); bool innerFirstReflow = InnerTableFrame()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW); nsRect origCaptionRect; nsRect origCaptionVisualOverflow; bool captionFirstReflow = false; if (mCaptionFrames.NotEmpty()) { origCaptionRect = mCaptionFrames.FirstChild()->GetRect(); origCaptionVisualOverflow = mCaptionFrames.FirstChild()->GetVisualOverflowRect(); captionFirstReflow = mCaptionFrames.FirstChild()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW); } // ComputeAutoSize has to match this logic. WritingMode wm = aOuterRI.GetWritingMode(); uint8_t captionSide = GetCaptionSide(); WritingMode captionWM = wm; // will be changed below if necessary if (captionSide == NO_SIDE) { // We don't have a caption. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI, innerRI, aOuterRI.ComputedSize(wm).ISize(wm)); } else if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT || captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) { // ComputeAutoSize takes care of making side captions small. Compute // the caption's size first, and tell the table to fit in what's left. OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRI, captionRI, aOuterRI.ComputedSize(wm).ISize(wm)); captionWM = captionRI->GetWritingMode(); nscoord innerAvailISize = aOuterRI.ComputedSize(wm).ISize(wm) - captionRI->ComputedSizeWithMarginBorderPadding(wm).ISize(wm); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI, innerRI, 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 larger in the inline dir 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 isize (if we did, // it would break 'auto' margins), but this effectively does that. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI, innerRI, aOuterRI.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 isize (ignoring the margin on one side if // neither are auto). (We take advantage of that later when we call // GetCaptionOrigin, though.) nscoord innerBorderISize = innerRI->ComputedSizeWithBorderPadding(wm).ISize(wm); OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRI, captionRI, innerBorderISize); captionWM = captionRI->GetWritingMode(); } 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. captionWM = mCaptionFrames.FirstChild()->GetWritingMode(); OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRI, captionRI, aOuterRI.ComputedSize(captionWM).ISize(captionWM)); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI, innerRI, aOuterRI.ComputedSize(wm).ISize(wm)); } // First reflow the caption. Maybe<ReflowOutput> captionMet; LogicalSize captionSize(wm); LogicalMargin captionMargin(wm); if (mCaptionFrames.NotEmpty()) { captionMet.emplace(wm); nsReflowStatus capStatus; // don't let the caption cause incomplete OuterDoReflowChild(aPresContext, mCaptionFrames.FirstChild(), *captionRI, *captionMet, capStatus); captionSize.ISize(wm) = captionMet->ISize(wm); captionSize.BSize(wm) = captionMet->BSize(wm); captionMargin = captionRI->ComputedLogicalMargin().ConvertTo(wm, captionWM); // Now that we know the bsize of the caption, reduce the available bsize // for the table frame if we are bsize constrained and the caption is above // or below the inner table. Also reduce the CB size that we store for // our children in case we're a grid item, by the same amount. LogicalSize* cbSize = Properties().Get(GridItemCBSizeProperty()); if (NS_UNCONSTRAINEDSIZE != aOuterRI.AvailableBSize() || cbSize) { nscoord captionBSize = 0; nscoord captionISize = 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: captionBSize = captionSize.BSize(wm) + captionMargin.BStartEnd(wm); break; case NS_STYLE_CAPTION_SIDE_LEFT: case NS_STYLE_CAPTION_SIDE_RIGHT: captionISize = captionSize.ISize(wm) + captionMargin.IStartEnd(wm); break; } if (NS_UNCONSTRAINEDSIZE != aOuterRI.AvailableBSize()) { innerRI->AvailableBSize() = std::max(0, innerRI->AvailableBSize() - captionBSize); } if (cbSize) { // Shrink the CB size by the size reserved for the caption. LogicalSize oldCBSize = *cbSize; cbSize->ISize(wm) = std::max(0, cbSize->ISize(wm) - captionISize); cbSize->BSize(wm) = std::max(0, cbSize->BSize(wm) - captionBSize); if (oldCBSize != *cbSize) { // Reset the inner table's ReflowInput to stretch it to the new size. innerRI.reset(); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI, innerRI, aOuterRI.ComputedSize(wm).ISize(wm)); } } } } // Then, now that we know how much to reduce the isize of the inner // table to account for side captions, reflow the inner table. ReflowOutput innerMet(innerRI->GetWritingMode()); OuterDoReflowChild(aPresContext, InnerTableFrame(), *innerRI, innerMet, aStatus); LogicalSize innerSize(wm, innerMet.ISize(wm), innerMet.BSize(wm)); LogicalMargin innerMargin = innerRI->ComputedLogicalMargin(); LogicalSize containSize(wm, GetContainingBlockSize(aOuterRI)); // 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.) // Compute the desiredSize so that we can use it as the containerSize // for the FinishReflowChild calls below. LogicalSize desiredSize(wm); SetDesiredSize(captionSide, innerSize, captionSize, innerMargin, captionMargin, desiredSize.ISize(wm), desiredSize.BSize(wm), wm); aDesiredSize.SetSize(wm, desiredSize); nsSize containerSize = aDesiredSize.PhysicalSize(); // XXX It's possible for this to be NS_UNCONSTRAINEDSIZE, which will result // in assertions from FinishReflowChild. if (mCaptionFrames.NotEmpty()) { LogicalPoint captionOrigin(wm); GetCaptionOrigin(captionSide, containSize, innerSize, innerMargin, captionSize, captionMargin, captionOrigin, wm); FinishReflowChild(mCaptionFrames.FirstChild(), aPresContext, *captionMet, captionRI.ptr(), wm, captionOrigin, containerSize, 0); captionRI.reset(); } // XXX If the bsize is constrained then we need to check whether // everything still fits... LogicalPoint innerOrigin(wm); GetInnerOrigin(captionSide, containSize, captionSize, captionMargin, innerSize, innerMargin, innerOrigin, wm); FinishReflowChild(InnerTableFrame(), aPresContext, innerMet, innerRI.ptr(), wm, innerOrigin, containerSize, 0); innerRI.reset(); nsTableFrame::InvalidateTableFrame(InnerTableFrame(), origInnerRect, origInnerVisualOverflow, innerFirstReflow); if (mCaptionFrames.NotEmpty()) { nsTableFrame::InvalidateTableFrame(mCaptionFrames.FirstChild(), origCaptionRect, origCaptionVisualOverflow, captionFirstReflow); } UpdateOverflowAreas(aDesiredSize); if (GetPrevInFlow()) { ReflowOverflowContainerChildren(aPresContext, aOuterRI, aDesiredSize.mOverflowAreas, 0, aStatus); } FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aOuterRI, aStatus); // Return our desired rect NS_FRAME_SET_TRUNCATION(aStatus, aOuterRI, aDesiredSize); }
void nsVideoFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsVideoFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsVideoFrame::Reflow: availSize=%d,%d", aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight())); NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); aStatus = NS_FRAME_COMPLETE; const WritingMode myWM = aReflowInput.GetWritingMode(); nscoord contentBoxBSize = aReflowInput.ComputedBSize(); const nscoord borderBoxISize = aReflowInput.ComputedISize() + aReflowInput.ComputedLogicalBorderPadding().IStartEnd(myWM); const bool isBSizeShrinkWrapping = (contentBoxBSize == NS_INTRINSICSIZE); nscoord borderBoxBSize; if (!isBSizeShrinkWrapping) { borderBoxBSize = contentBoxBSize + aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM); } nsMargin borderPadding = aReflowInput.ComputedPhysicalBorderPadding(); // Reflow the child frames. We may have up to three: an image // frame (for the poster image), a container frame for the controls, // and a container frame for the caption. for (nsIFrame* child : mFrames) { nsSize oldChildSize = child->GetSize(); if (child->GetContent() == mPosterImage) { // Reflow the poster frame. nsImageFrame* imageFrame = static_cast<nsImageFrame*>(child); ReflowOutput kidDesiredSize(aReflowInput); WritingMode wm = imageFrame->GetWritingMode(); LogicalSize availableSize = aReflowInput.AvailableSize(wm); LogicalSize cbSize = aMetrics.Size(aMetrics.GetWritingMode()). ConvertTo(wm, aMetrics.GetWritingMode()); ReflowInput kidReflowInput(aPresContext, aReflowInput, imageFrame, availableSize, &cbSize); nsRect posterRenderRect; if (ShouldDisplayPoster()) { posterRenderRect = nsRect(nsPoint(borderPadding.left, borderPadding.top), nsSize(aReflowInput.ComputedWidth(), aReflowInput.ComputedHeight())); } kidReflowInput.SetComputedWidth(posterRenderRect.width); kidReflowInput.SetComputedHeight(posterRenderRect.height); ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowInput, posterRenderRect.x, posterRenderRect.y, 0, aStatus); FinishReflowChild(imageFrame, aPresContext, kidDesiredSize, &kidReflowInput, posterRenderRect.x, posterRenderRect.y, 0); // Android still uses XUL media controls & hence needs this XUL-friendly // custom reflow code. This will go away in bug 1310907. #ifdef ANDROID } else if (child->GetContent() == mVideoControls) { // Reflow the video controls frame. nsBoxLayoutState boxState(PresContext(), aReflowInput.mRenderingContext); nsBoxFrame::LayoutChildAt(boxState, child, nsRect(borderPadding.left, borderPadding.top, aReflowInput.ComputedWidth(), aReflowInput.ComputedHeight())); #endif // ANDROID } else if (child->GetContent() == mCaptionDiv || child->GetContent() == mVideoControls) { // Reflow the caption and control bar frames. WritingMode wm = child->GetWritingMode(); LogicalSize availableSize = aReflowInput.ComputedSize(wm); availableSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; ReflowInput kidReflowInput(aPresContext, aReflowInput, child, availableSize); ReflowOutput kidDesiredSize(kidReflowInput); ReflowChild(child, aPresContext, kidDesiredSize, kidReflowInput, borderPadding.left, borderPadding.top, 0, aStatus); if (child->GetContent() == mVideoControls && isBSizeShrinkWrapping) { // Resolve our own BSize based on the controls' size in the same axis. contentBoxBSize = myWM.IsOrthogonalTo(wm) ? kidDesiredSize.ISize(wm) : kidDesiredSize.BSize(wm); } FinishReflowChild(child, aPresContext, kidDesiredSize, &kidReflowInput, borderPadding.left, borderPadding.top, 0); } if (child->GetContent() == mVideoControls && child->GetSize() != oldChildSize) { RefPtr<Runnable> event = new DispatchResizeToControls(child->GetContent()); nsContentUtils::AddScriptRunner(event); } } if (isBSizeShrinkWrapping) { if (contentBoxBSize == NS_INTRINSICSIZE) { // We didn't get a BSize from our intrinsic size/ratio, nor did we // get one from our controls. Just use BSize of 0. contentBoxBSize = 0; } contentBoxBSize = NS_CSS_MINMAX(contentBoxBSize, aReflowInput.ComputedMinBSize(), aReflowInput.ComputedMaxBSize()); borderBoxBSize = contentBoxBSize + aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM); } LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize); aMetrics.SetSize(myWM, logicalDesiredSize); aMetrics.SetOverflowAreasToDesiredBounds(); FinishAndStoreOverflow(&aMetrics); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsVideoFrame::Reflow: size=%d,%d", aMetrics.Width(), aMetrics.Height())); NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics); }
BlockReflowInput::BlockReflowInput(const ReflowInput& aReflowInput, nsPresContext* aPresContext, nsBlockFrame* aFrame, bool aBStartMarginRoot, bool aBEndMarginRoot, bool aBlockNeedsFloatManager, nscoord aConsumedBSize) : mBlock(aFrame), mPresContext(aPresContext), mReflowInput(aReflowInput), mContentArea(aReflowInput.GetWritingMode()), mPushedFloats(nullptr), mOverflowTracker(nullptr), mBorderPadding(mReflowInput.ComputedLogicalBorderPadding()), mPrevBEndMargin(), mLineNumber(0), mFloatBreakType(StyleClear::None), mConsumedBSize(aConsumedBSize) { if (!sFloatFragmentsInsideColumnPrefCached) { sFloatFragmentsInsideColumnPrefCached = true; Preferences::AddBoolVarCache(&sFloatFragmentsInsideColumnEnabled, "layout.float-fragments-inside-column.enabled"); } mFlags.mFloatFragmentsInsideColumnEnabled = sFloatFragmentsInsideColumnEnabled; WritingMode wm = aReflowInput.GetWritingMode(); mFlags.mIsFirstInflow = !aFrame->GetPrevInFlow(); mFlags.mIsOverflowContainer = IS_TRUE_OVERFLOW_CONTAINER(aFrame); nsIFrame::LogicalSides logicalSkipSides = aFrame->GetLogicalSkipSides(&aReflowInput); mBorderPadding.ApplySkipSides(logicalSkipSides); // Note that mContainerSize is the physical size, needed to // convert logical block-coordinates in vertical-rl writing mode // (measured from a RHS origin) to physical coordinates within the // containing block. // If aReflowInput doesn't have a constrained ComputedWidth(), we set // mContainerSize.width to zero, which means lines will be positioned // (physically) incorrectly; we will fix them up at the end of // nsBlockFrame::Reflow, after we know the total block-size of the // frame. mContainerSize.width = aReflowInput.ComputedWidth(); if (mContainerSize.width == NS_UNCONSTRAINEDSIZE) { mContainerSize.width = 0; } mContainerSize.width += mBorderPadding.LeftRight(wm); // For now at least, we don't do that fix-up for mContainerHeight. // It's only used in nsBidiUtils::ReorderFrames for vertical rtl // writing modes, which aren't fully supported for the time being. mContainerSize.height = aReflowInput.ComputedHeight() + mBorderPadding.TopBottom(wm); if ((aBStartMarginRoot && !logicalSkipSides.BStart()) || 0 != mBorderPadding.BStart(wm)) { mFlags.mIsBStartMarginRoot = true; mFlags.mShouldApplyBStartMargin = true; } if ((aBEndMarginRoot && !logicalSkipSides.BEnd()) || 0 != mBorderPadding.BEnd(wm)) { mFlags.mIsBEndMarginRoot = true; } if (aBlockNeedsFloatManager) { mFlags.mBlockNeedsFloatManager = true; } mFloatManager = aReflowInput.mFloatManager; NS_ASSERTION(mFloatManager, "FloatManager should be set in BlockReflowInput" ); if (mFloatManager) { // Save the coordinate system origin for later. mFloatManager->GetTranslation(mFloatManagerI, mFloatManagerB); mFloatManager->PushState(&mFloatManagerStateBefore); // never popped } mReflowStatus = NS_FRAME_COMPLETE; mNextInFlow = static_cast<nsBlockFrame*>(mBlock->GetNextInFlow()); LAYOUT_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedISize(), "have unconstrained width; this should only result " "from very large sizes, not attempts at intrinsic " "width calculation"); mContentArea.ISize(wm) = aReflowInput.ComputedISize(); // Compute content area height. Unlike the width, if we have a // specified style height we ignore it since extra content is // managed by the "overflow" property. When we don't have a // specified style height then we may end up limiting our height if // the availableHeight is constrained (this situation occurs when we // are paginated). if (NS_UNCONSTRAINEDSIZE != aReflowInput.AvailableBSize()) { // We are in a paginated situation. The bottom edge is just inside // the bottom border and padding. The content area height doesn't // include either border or padding edge. mBEndEdge = aReflowInput.AvailableBSize() - mBorderPadding.BEnd(wm); mContentArea.BSize(wm) = std::max(0, mBEndEdge - mBorderPadding.BStart(wm)); } else { // When we are not in a paginated situation then we always use // a constrained height. mFlags.mHasUnconstrainedBSize = true; mContentArea.BSize(wm) = mBEndEdge = NS_UNCONSTRAINEDSIZE; } mContentArea.IStart(wm) = mBorderPadding.IStart(wm); mBCoord = mContentArea.BStart(wm) = mBorderPadding.BStart(wm); mPrevChild = nullptr; mCurrentLine = aFrame->LinesEnd(); mMinLineHeight = aReflowInput.CalcLineHeight(); }
void ViewportFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("ViewportFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow"); // Initialize OUT parameters aStatus = NS_FRAME_COMPLETE; // Because |Reflow| sets ComputedBSize() on the child to our // ComputedBSize(). AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE); // 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(aReflowInput.ComputedWidth(), aReflowInput.ComputedHeight())); // Reflow the main content first so that the placeholders of the // fixed-position frames will be in the right places on an initial // reflow. nscoord kidBSize = 0; WritingMode wm = aReflowInput.GetWritingMode(); if (mFrames.NotEmpty()) { // Deal with a non-incremental reflow or an incremental reflow // targeted at our one-and-only principal child frame. if (aReflowInput.ShouldReflowAllKids() || aReflowInput.IsBResize() || NS_SUBTREE_DIRTY(mFrames.FirstChild())) { // Reflow our one-and-only principal child frame nsIFrame* kidFrame = mFrames.FirstChild(); ReflowOutput kidDesiredSize(aReflowInput); WritingMode wm = kidFrame->GetWritingMode(); LogicalSize availableSpace = aReflowInput.AvailableSize(wm); ReflowInput kidReflowInput(aPresContext, aReflowInput, kidFrame, availableSpace); // Reflow the frame kidReflowInput.SetComputedBSize(aReflowInput.ComputedBSize()); ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowInput, 0, 0, 0, aStatus); kidBSize = kidDesiredSize.BSize(wm); FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, nullptr, 0, 0, 0); } else { kidBSize = LogicalSize(wm, mFrames.FirstChild()->GetSize()).BSize(wm); } } NS_ASSERTION(aReflowInput.AvailableISize() != NS_UNCONSTRAINEDSIZE, "shouldn't happen anymore"); // Return the max size as our desired size LogicalSize maxSize(wm, aReflowInput.AvailableISize(), // Being flowed initially at an unconstrained block size // means we should return our child's intrinsic size. aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE ? aReflowInput.ComputedBSize() : kidBSize); aDesiredSize.SetSize(wm, maxSize); aDesiredSize.SetOverflowAreasToDesiredBounds(); if (HasAbsolutelyPositionedChildren()) { // Make a copy of the reflow state and change the computed width and height // to reflect the available space for the fixed items ReflowInput reflowInput(aReflowInput); if (reflowInput.AvailableBSize() == NS_UNCONSTRAINEDSIZE) { // We have an intrinsic-height document with abs-pos/fixed-pos children. // Set the available height and mComputedHeight to our chosen height. reflowInput.AvailableBSize() = maxSize.BSize(wm); // Not having border/padding simplifies things NS_ASSERTION(reflowInput.ComputedPhysicalBorderPadding() == nsMargin(0,0,0,0), "Viewports can't have border/padding"); reflowInput.SetComputedBSize(maxSize.BSize(wm)); } nsRect rect = AdjustReflowInputAsContainingBlock(&reflowInput); nsOverflowAreas* overflowAreas = &aDesiredSize.mOverflowAreas; nsIScrollableFrame* rootScrollFrame = aPresContext->PresShell()->GetRootScrollFrameAsScrollable(); if (rootScrollFrame && !rootScrollFrame->IsIgnoringViewportClipping()) { overflowAreas = nullptr; } AbsPosReflowFlags flags = AbsPosReflowFlags::eCBWidthAndHeightChanged; // XXX could be optimized GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowInput, aStatus, rect, flags, overflowAreas); } if (mFrames.NotEmpty()) { ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mFrames.FirstChild()); } // If we were dirty then do a repaint if (GetStateBits() & NS_FRAME_IS_DIRTY) { InvalidateFrame(); } // Clipping is handled by the document container (e.g., nsSubDocumentFrame), // so we don't need to change our overflow areas. bool overflowChanged = FinishAndStoreOverflow(&aDesiredSize); if (overflowChanged) { // We may need to alert our container to get it to pick up the // overflow change. nsSubDocumentFrame* container = static_cast<nsSubDocumentFrame*> (nsLayoutUtils::GetCrossDocParentFrame(this)); if (container && !container->ShouldClipSubdocument()) { container->PresContext()->PresShell()-> FrameNeedsReflow(container, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); } } NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus); NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); }
/* virtual */ void nsRubyFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsRubyFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); if (!aReflowInput.mLineLayout) { NS_ASSERTION(aReflowInput.mLineLayout, "No line layout provided to RubyFrame reflow method."); return; } // Grab overflow frames from prev-in-flow and its own. MoveInlineOverflowToChildList( aReflowInput.mLineLayout->LineContainerFrame()); // Clear leadings mLeadings.Reset(); // Since the ruby base container is going to reflow not only the ruby // base frames, but also the ruby text frames, and then *afterwards* // we're going to reflow the ruby text containers (which do not reflow // their children), we need to transfer NS_FRAME_IS_DIRTY status from // the ruby text containers to their child ruby texts now, both so // that the ruby texts are marked dirty if needed, and so that the // ruby text container doesn't mark the ruby text frames dirty *after* // they're reflowed and leave dirty bits in a clean tree (suppressing // future reflows, due to lack of a queued reflow to clean them). for (nsIFrame* child : PrincipalChildList()) { if (child->HasAnyStateBits(NS_FRAME_IS_DIRTY) && child->IsRubyTextContainerFrame()) { for (nsIFrame* grandchild : child->PrincipalChildList()) { grandchild->AddStateBits(NS_FRAME_IS_DIRTY); } // Replace NS_FRAME_IS_DIRTY with NS_FRAME_HAS_DIRTY_CHILDREN so // we still have a dirty marking, but one that we won't transfer // to children again. child->RemoveStateBits(NS_FRAME_IS_DIRTY); child->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); } } // Begin the span for the ruby frame WritingMode frameWM = aReflowInput.GetWritingMode(); WritingMode lineWM = aReflowInput.mLineLayout->GetWritingMode(); LogicalMargin borderPadding = aReflowInput.ComputedLogicalBorderPadding(); nscoord startEdge = 0; const bool boxDecorationBreakClone = StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone; if (boxDecorationBreakClone || !GetPrevContinuation()) { startEdge = borderPadding.IStart(frameWM); } NS_ASSERTION(aReflowInput.AvailableISize() != NS_UNCONSTRAINEDSIZE, "should no longer use available widths"); nscoord availableISize = aReflowInput.AvailableISize(); availableISize -= startEdge + borderPadding.IEnd(frameWM); aReflowInput.mLineLayout->BeginSpan(this, &aReflowInput, startEdge, availableISize, &mBaseline); for (RubySegmentEnumerator e(this); !e.AtEnd(); e.Next()) { ReflowSegment(aPresContext, aReflowInput, e.GetBaseContainer(), aStatus); if (aStatus.IsInlineBreak()) { // A break occurs when reflowing the segment. // Don't continue reflowing more segments. break; } } ContinuationTraversingState pullState(this); while (aStatus.IsEmpty()) { nsRubyBaseContainerFrame* baseContainer = PullOneSegment(aReflowInput.mLineLayout, pullState); if (!baseContainer) { // No more continuations after, finish now. break; } ReflowSegment(aPresContext, aReflowInput, baseContainer, aStatus); } // We never handle overflow in ruby. MOZ_ASSERT(!aStatus.IsOverflowIncomplete()); aDesiredSize.ISize(lineWM) = aReflowInput.mLineLayout->EndSpan(this); if (boxDecorationBreakClone || !GetPrevContinuation()) { aDesiredSize.ISize(lineWM) += borderPadding.IStart(frameWM); } if (boxDecorationBreakClone || aStatus.IsComplete()) { aDesiredSize.ISize(lineWM) += borderPadding.IEnd(frameWM); } // Update descendant leadings of ancestor ruby base container. if (nsRubyBaseContainerFrame* rbc = FindRubyBaseContainerAncestor(this)) { rbc->UpdateDescendantLeadings(mLeadings); } nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, borderPadding, lineWM, frameWM); }
void nsInlineFrame::ReflowFrames(nsPresContext* aPresContext, const ReflowInput& aReflowInput, InlineReflowInput& irs, ReflowOutput& aMetrics, nsReflowStatus& aStatus) { MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); nsLineLayout* lineLayout = aReflowInput.mLineLayout; bool inFirstLine = aReflowInput.mLineLayout->GetInFirstLine(); RestyleManager* restyleManager = aPresContext->RestyleManager(); WritingMode frameWM = aReflowInput.GetWritingMode(); WritingMode lineWM = aReflowInput.mLineLayout->mRootSpan->mWritingMode; LogicalMargin framePadding = aReflowInput.ComputedLogicalBorderPadding(); nscoord startEdge = 0; const bool boxDecorationBreakClone = MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone); // Don't offset by our start borderpadding if we have a prev continuation or // if we're in a part of an {ib} split other than the first one. For // box-decoration-break:clone we always offset our start since all // continuations have border/padding. if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) || boxDecorationBreakClone) { startEdge = framePadding.IStart(frameWM); } nscoord availableISize = aReflowInput.AvailableISize(); NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE, "should no longer use available widths"); // Subtract off inline axis border+padding from availableISize availableISize -= startEdge; availableISize -= framePadding.IEnd(frameWM); lineLayout->BeginSpan(this, &aReflowInput, startEdge, startEdge + availableISize, &mBaseline); // First reflow our principal children. nsIFrame* frame = mFrames.FirstChild(); bool done = false; while (frame) { // Check if we should lazily set the child frame's parent pointer. if (irs.mSetParentPointer) { nsIFrame* child = frame; do { child->SetParent(this); if (inFirstLine) { restyleManager->ReparentStyleContext(child); nsLayoutUtils::MarkDescendantsDirty(child); } // We also need to do the same for |frame|'s next-in-flows that are in // the sibling list. Otherwise, if we reflow |frame| and it's complete // we'll crash when trying to delete its next-in-flow. // This scenario doesn't happen often, but it can happen. nsIFrame* nextSibling = child->GetNextSibling(); child = child->GetNextInFlow(); if (MOZ_UNLIKELY(child)) { while (child != nextSibling && nextSibling) { nextSibling = nextSibling->GetNextSibling(); } if (!nextSibling) { child = nullptr; } } MOZ_ASSERT(!child || mFrames.ContainsFrame(child)); } while (child); // Fix the parent pointer for ::first-letter child frame next-in-flows, // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042). nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame); if (realFrame->IsLetterFrame()) { nsIFrame* child = realFrame->PrincipalChildList().FirstChild(); if (child) { NS_ASSERTION(child->IsTextFrame(), "unexpected frame type"); nsIFrame* nextInFlow = child->GetNextInFlow(); for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) { NS_ASSERTION(nextInFlow->IsTextFrame(), "unexpected frame type"); if (mFrames.ContainsFrame(nextInFlow)) { nextInFlow->SetParent(this); if (inFirstLine) { restyleManager->ReparentStyleContext(nextInFlow); nsLayoutUtils::MarkDescendantsDirty(nextInFlow); } } else { #ifdef DEBUG // Once we find a next-in-flow that isn't ours none of the // remaining next-in-flows should be either. for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) { NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow), "unexpected letter frame flow"); } #endif break; } } } } } MOZ_ASSERT(frame->GetParent() == this); if (!done) { bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); ReflowInlineFrame(aPresContext, aReflowInput, irs, frame, aStatus); done = aStatus.IsInlineBreak() || (!reflowingFirstLetter && aStatus.IsIncomplete()); if (done) { if (!irs.mSetParentPointer) { break; } // Keep reparenting the remaining siblings, but don't reflow them. nsFrameList* pushedFrames = GetOverflowFrames(); if (pushedFrames && pushedFrames->FirstChild() == frame) { // Don't bother if |frame| was pushed to our overflow list. break; } } else { irs.mPrevFrame = frame; } } frame = frame->GetNextSibling(); } // Attempt to pull frames from our next-in-flow until we can't if (!done && GetNextInFlow()) { while (true) { bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); bool isComplete; if (!frame) { // Could be non-null if we pulled a first-letter frame and // it created a continuation, since we don't push those. frame = PullOneFrame(aPresContext, irs, &isComplete); } #ifdef NOISY_PUSHING printf("%p pulled up %p\n", this, frame); #endif if (nullptr == frame) { if (!isComplete) { aStatus.Reset(); aStatus.SetIncomplete(); } break; } ReflowInlineFrame(aPresContext, aReflowInput, irs, frame, aStatus); if (aStatus.IsInlineBreak() || (!reflowingFirstLetter && aStatus.IsIncomplete())) { break; } irs.mPrevFrame = frame; frame = frame->GetNextSibling(); } } NS_ASSERTION(!aStatus.IsComplete() || !GetOverflowFrames(), "We can't be complete AND have overflow frames!"); // If after reflowing our children they take up no area then make // sure that we don't either. // // Note: CSS demands that empty inline elements still affect the // line-height calculations. However, continuations of an inline // that are empty we force to empty so that things like collapsed // whitespace in an inline element don't affect the line-height. aMetrics.ISize(lineWM) = lineLayout->EndSpan(this); // Compute final width. // XXX Note that that the padding start and end are in the frame's // writing mode, but the metrics' inline-size is in the line's // writing mode. This makes sense if the line and frame are both // vertical or both horizontal, but what should happen with // orthogonal inlines? // Make sure to not include our start border and padding if we have a prev // continuation or if we're in a part of an {ib} split other than the first // one. For box-decoration-break:clone we always include our start border // and padding since all continuations have them. if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) || boxDecorationBreakClone) { aMetrics.ISize(lineWM) += framePadding.IStart(frameWM); } /* * We want to only apply the end border and padding if we're the last * continuation and either not in an {ib} split or the last part of it. To * be the last continuation we have to be complete (so that we won't get a * next-in-flow) and have no non-fluid continuations on our continuation * chain. For box-decoration-break:clone we always apply the end border and * padding since all continuations have them. */ if ((aStatus.IsComplete() && !LastInFlow()->GetNextContinuation() && !FrameIsNonLastInIBSplit()) || boxDecorationBreakClone) { aMetrics.ISize(lineWM) += framePadding.IEnd(frameWM); } nsLayoutUtils::SetBSizeFromFontMetrics(this, aMetrics, framePadding, lineWM, frameWM); // For now our overflow area is zero. The real value will be // computed in |nsLineLayout::RelativePositionFrames|. aMetrics.mOverflowAreas.Clear(); #ifdef NOISY_FINAL_SIZE ListTag(stdout); printf(": metrics=%d,%d ascent=%d\n", aMetrics.Width(), aMetrics.Height(), aMetrics.TopAscent()); #endif }
void nsAbsoluteContainingBlock::ResolveSizeDependentOffsets( nsPresContext* aPresContext, ReflowInput& aKidReflowInput, const LogicalSize& aKidSize, const LogicalMargin& aMargin, LogicalMargin* aOffsets, LogicalSize* aLogicalCBSize) { WritingMode wm = aKidReflowInput.GetWritingMode(); WritingMode outerWM = aKidReflowInput.mParentReflowInput->GetWritingMode(); // Now that we know the child's size, we resolve any sentinel values in its // IStart/BStart offset coordinates that depend on that size. // * NS_AUTOOFFSET indicates that the child's position in the given axis // is determined by its end-wards offset property, combined with its size and // available space. e.g.: "top: auto; height: auto; bottom: 50px" // * m{I,B}OffsetsResolvedAfterSize indicate that the child is using its // static position in that axis, *and* its static position is determined by // the axis-appropriate css-align property (which may require the child's // size, e.g. to center it within the parent). if ((NS_AUTOOFFSET == aOffsets->IStart(outerWM)) || (NS_AUTOOFFSET == aOffsets->BStart(outerWM)) || aKidReflowInput.mFlags.mIOffsetsNeedCSSAlign || aKidReflowInput.mFlags.mBOffsetsNeedCSSAlign) { if (-1 == aLogicalCBSize->ISize(wm)) { // Get the containing block width/height const ReflowInput* parentRI = aKidReflowInput.mParentReflowInput; *aLogicalCBSize = aKidReflowInput.ComputeContainingBlockRectangle(aPresContext, parentRI); } const LogicalSize logicalCBSizeOuterWM = aLogicalCBSize->ConvertTo(outerWM, wm); // placeholderContainer is used in each of the m{I,B}OffsetsNeedCSSAlign // clauses. We declare it at this scope so we can avoid having to look // it up twice (and only look it up if it's needed). nsContainerFrame* placeholderContainer = nullptr; if (NS_AUTOOFFSET == aOffsets->IStart(outerWM)) { NS_ASSERTION(NS_AUTOOFFSET != aOffsets->IEnd(outerWM), "Can't solve for both start and end"); aOffsets->IStart(outerWM) = logicalCBSizeOuterWM.ISize(outerWM) - aOffsets->IEnd(outerWM) - aMargin.IStartEnd(outerWM) - aKidSize.ISize(outerWM); } else if (aKidReflowInput.mFlags.mIOffsetsNeedCSSAlign) { placeholderContainer = GetPlaceholderContainer(aPresContext, aKidReflowInput.mFrame); nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize, placeholderContainer, outerWM, eLogicalAxisInline); // Shift IStart from its current position (at start corner of the // alignment container) by the returned offset. And set IEnd to the // distance between the kid's end edge to containing block's end edge. aOffsets->IStart(outerWM) += offset; aOffsets->IEnd(outerWM) = logicalCBSizeOuterWM.ISize(outerWM) - (aOffsets->IStart(outerWM) + aKidSize.ISize(outerWM)); } if (NS_AUTOOFFSET == aOffsets->BStart(outerWM)) { aOffsets->BStart(outerWM) = logicalCBSizeOuterWM.BSize(outerWM) - aOffsets->BEnd(outerWM) - aMargin.BStartEnd(outerWM) - aKidSize.BSize(outerWM); } else if (aKidReflowInput.mFlags.mBOffsetsNeedCSSAlign) { if (!placeholderContainer) { placeholderContainer = GetPlaceholderContainer(aPresContext, aKidReflowInput.mFrame); } nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize, placeholderContainer, outerWM, eLogicalAxisBlock); // Shift BStart from its current position (at start corner of the // alignment container) by the returned offset. And set BEnd to the // distance between the kid's end edge to containing block's end edge. aOffsets->BStart(outerWM) += offset; aOffsets->BEnd(outerWM) = logicalCBSizeOuterWM.BSize(outerWM) - (aOffsets->BStart(outerWM) + aKidSize.BSize(outerWM)); } aKidReflowInput.SetComputedLogicalOffsets(aOffsets->ConvertTo(wm, outerWM)); } }
/* virtual */ void nsRubyFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsRubyFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); if (!aReflowInput.mLineLayout) { NS_ASSERTION(aReflowInput.mLineLayout, "No line layout provided to RubyFrame reflow method."); aStatus = NS_FRAME_COMPLETE; return; } // Grab overflow frames from prev-in-flow and its own. MoveOverflowToChildList(); // Clear leadings mBStartLeading = mBEndLeading = 0; // Begin the span for the ruby frame WritingMode frameWM = aReflowInput.GetWritingMode(); WritingMode lineWM = aReflowInput.mLineLayout->GetWritingMode(); LogicalMargin borderPadding = aReflowInput.ComputedLogicalBorderPadding(); nscoord startEdge = 0; const bool boxDecorationBreakClone = StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone; if (boxDecorationBreakClone || !GetPrevContinuation()) { startEdge = borderPadding.IStart(frameWM); } NS_ASSERTION(aReflowInput.AvailableISize() != NS_UNCONSTRAINEDSIZE, "should no longer use available widths"); nscoord availableISize = aReflowInput.AvailableISize(); availableISize -= startEdge + borderPadding.IEnd(frameWM); aReflowInput.mLineLayout->BeginSpan(this, &aReflowInput, startEdge, availableISize, &mBaseline); aStatus = NS_FRAME_COMPLETE; for (RubySegmentEnumerator e(this); !e.AtEnd(); e.Next()) { ReflowSegment(aPresContext, aReflowInput, e.GetBaseContainer(), aStatus); if (NS_INLINE_IS_BREAK(aStatus)) { // A break occurs when reflowing the segment. // Don't continue reflowing more segments. break; } } ContinuationTraversingState pullState(this); while (aStatus == NS_FRAME_COMPLETE) { nsRubyBaseContainerFrame* baseContainer = PullOneSegment(aReflowInput.mLineLayout, pullState); if (!baseContainer) { // No more continuations after, finish now. break; } ReflowSegment(aPresContext, aReflowInput, baseContainer, aStatus); } // We never handle overflow in ruby. MOZ_ASSERT(!NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)); aDesiredSize.ISize(lineWM) = aReflowInput.mLineLayout->EndSpan(this); if (boxDecorationBreakClone || !GetPrevContinuation()) { aDesiredSize.ISize(lineWM) += borderPadding.IStart(frameWM); } if (boxDecorationBreakClone || NS_FRAME_IS_COMPLETE(aStatus)) { aDesiredSize.ISize(lineWM) += borderPadding.IEnd(frameWM); } nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, borderPadding, lineWM, frameWM); }
void nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame, nsPresContext* aPresContext, const ReflowInput& aReflowInput, const nsRect& aContainingBlock, AbsPosReflowFlags aFlags, nsIFrame* aKidFrame, nsReflowStatus& aStatus, nsOverflowAreas* aOverflowAreas) { #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent); printf("abs pos "); nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); char width[16]; char height[16]; PrettyUC(aReflowInput.AvailableWidth(), width, 16); PrettyUC(aReflowInput.AvailableHeight(), height, 16); printf(" a=%s,%s ", width, height); PrettyUC(aReflowInput.ComputedWidth(), width, 16); PrettyUC(aReflowInput.ComputedHeight(), height, 16); printf("c=%s,%s \n", width, height); } AutoNoisyIndenter indent(nsBlockFrame::gNoisy); #endif // DEBUG WritingMode wm = aKidFrame->GetWritingMode(); LogicalSize logicalCBSize(wm, aContainingBlock.Size()); nscoord availISize = logicalCBSize.ISize(wm); if (availISize == -1) { NS_ASSERTION(aReflowInput.ComputedSize(wm).ISize(wm) != NS_UNCONSTRAINEDSIZE, "Must have a useful inline-size _somewhere_"); availISize = aReflowInput.ComputedSizeWithPadding(wm).ISize(wm); } uint32_t rsFlags = 0; if (aFlags & AbsPosReflowFlags::eIsGridContainerCB) { // When a grid container generates the abs.pos. CB for a *child* then // the static-position is the CB origin (i.e. of the grid area rect). // https://drafts.csswg.org/css-grid/#static-position nsIFrame* placeholder = aPresContext->PresShell()->GetPlaceholderFrameFor(aKidFrame); if (placeholder && placeholder->GetParent() == aDelegatingFrame) { rsFlags |= ReflowInput::STATIC_POS_IS_CB_ORIGIN; } } ReflowInput kidReflowInput(aPresContext, aReflowInput, aKidFrame, LogicalSize(wm, availISize, NS_UNCONSTRAINEDSIZE), &logicalCBSize, rsFlags); // Get the border values WritingMode outerWM = aReflowInput.GetWritingMode(); const LogicalMargin border(outerWM, aReflowInput.mStyleBorder->GetComputedBorder()); LogicalMargin margin = kidReflowInput.ComputedLogicalMargin().ConvertTo(outerWM, wm); // If we're doing CSS Box Alignment in either axis, that will apply the // margin for us in that axis (since the thing that's aligned is the margin // box). So, we clear out the margin here to avoid applying it twice. if (kidReflowInput.mFlags.mIOffsetsNeedCSSAlign) { margin.IStart(outerWM) = margin.IEnd(outerWM) = 0; } if (kidReflowInput.mFlags.mBOffsetsNeedCSSAlign) { margin.BStart(outerWM) = margin.BEnd(outerWM) = 0; } bool constrainBSize = (aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE) && (aFlags & AbsPosReflowFlags::eConstrainHeight) // Don't split if told not to (e.g. for fixed frames) && (aDelegatingFrame->GetType() != nsGkAtoms::inlineFrame) //XXX we don't handle splitting frames for inline absolute containing blocks yet && (aKidFrame->GetLogicalRect(aContainingBlock.Size()).BStart(wm) <= aReflowInput.AvailableBSize()); // Don't split things below the fold. (Ideally we shouldn't *have* // anything totally below the fold, but we can't position frames // across next-in-flow breaks yet. if (constrainBSize) { kidReflowInput.AvailableBSize() = aReflowInput.AvailableBSize() - border.ConvertTo(wm, outerWM).BStart(wm) - kidReflowInput.ComputedLogicalMargin().BStart(wm); if (NS_AUTOOFFSET != kidReflowInput.ComputedLogicalOffsets().BStart(wm)) { kidReflowInput.AvailableBSize() -= kidReflowInput.ComputedLogicalOffsets().BStart(wm); } } // Do the reflow ReflowOutput kidDesiredSize(kidReflowInput); aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowInput, aStatus); const LogicalSize kidSize = kidDesiredSize.Size(wm).ConvertTo(outerWM, wm); LogicalMargin offsets = kidReflowInput.ComputedLogicalOffsets().ConvertTo(outerWM, wm); // If we're solving for start in either inline or block direction, // then compute it now that we know the dimensions. ResolveSizeDependentOffsets(aPresContext, kidReflowInput, kidSize, margin, &offsets, &logicalCBSize); // Position the child relative to our padding edge LogicalRect rect(outerWM, border.IStart(outerWM) + offsets.IStart(outerWM) + margin.IStart(outerWM), border.BStart(outerWM) + offsets.BStart(outerWM) + margin.BStart(outerWM), kidSize.ISize(outerWM), kidSize.BSize(outerWM)); nsRect r = rect.GetPhysicalRect(outerWM, logicalCBSize.GetPhysicalSize(wm) + border.Size(outerWM).GetPhysicalSize(outerWM)); // Offset the frame rect by the given origin of the absolute containing block. // If the frame is auto-positioned on both sides of an axis, it will be // positioned based on its containing block and we don't need to offset // (unless the caller demands it (the STATIC_POS_IS_CB_ORIGIN case)). if (aContainingBlock.TopLeft() != nsPoint(0, 0)) { const nsStyleSides& offsets = kidReflowInput.mStylePosition->mOffset; if (!(offsets.GetLeftUnit() == eStyleUnit_Auto && offsets.GetRightUnit() == eStyleUnit_Auto) || (rsFlags & ReflowInput::STATIC_POS_IS_CB_ORIGIN)) { r.x += aContainingBlock.x; } if (!(offsets.GetTopUnit() == eStyleUnit_Auto && offsets.GetBottomUnit() == eStyleUnit_Auto) || (rsFlags & ReflowInput::STATIC_POS_IS_CB_ORIGIN)) { r.y += aContainingBlock.y; } } aKidFrame->SetRect(r); nsView* view = aKidFrame->GetView(); if (view) { // Size and position the view and set its opacity, visibility, content // transparency, and clip nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aKidFrame, view, kidDesiredSize.VisualOverflow()); } else { nsContainerFrame::PositionChildViews(aKidFrame); } aKidFrame->DidReflow(aPresContext, &kidReflowInput, nsDidReflowStatus::FINISHED); #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1); printf("abs pos "); nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); printf("%p rect=%d,%d,%d,%d\n", static_cast<void*>(aKidFrame), r.x, r.y, r.width, r.height); } #endif if (aOverflowAreas) { aOverflowAreas->UnionWith(kidDesiredSize.mOverflowAreas + r.TopLeft()); } }