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 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); }
/* virtual */ void nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsRubyBaseContainerFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); aStatus = NS_FRAME_COMPLETE; if (!aReflowInput.mLineLayout) { NS_ASSERTION( aReflowInput.mLineLayout, "No line layout provided to RubyBaseContainerFrame reflow method."); return; } mDescendantLeadings.Reset(); MoveOverflowToChildList(); // Ask text containers to drain overflows AutoRubyTextContainerArray textContainers(this); const uint32_t rtcCount = textContainers.Length(); for (uint32_t i = 0; i < rtcCount; i++) { textContainers[i]->MoveOverflowToChildList(); } WritingMode lineWM = aReflowInput.mLineLayout->GetWritingMode(); LogicalSize availSize(lineWM, aReflowInput.AvailableISize(), aReflowInput.AvailableBSize()); // We have a reflow state and a line layout for each RTC. // They are conceptually the state of the RTCs, but we don't actually // reflow those RTCs in this code. These two arrays are holders of // the reflow states and line layouts. // Since there are pointers refer to reflow states and line layouts, // it is necessary to guarantee that they won't be moved. For this // reason, they are wrapped in UniquePtr here. AutoTArray<UniquePtr<ReflowInput>, RTC_ARRAY_SIZE> reflowInputs; AutoTArray<UniquePtr<nsLineLayout>, RTC_ARRAY_SIZE> lineLayouts; reflowInputs.SetCapacity(rtcCount); lineLayouts.SetCapacity(rtcCount); // Begin the line layout for each ruby text container in advance. bool hasSpan = false; for (uint32_t i = 0; i < rtcCount; i++) { nsRubyTextContainerFrame* textContainer = textContainers[i]; if (textContainer->IsSpanContainer()) { hasSpan = true; } ReflowInput* reflowInput = new ReflowInput( aPresContext, *aReflowInput.mParentReflowInput, textContainer, availSize.ConvertTo(textContainer->GetWritingMode(), lineWM)); reflowInputs.AppendElement(reflowInput); nsLineLayout* lineLayout = new nsLineLayout(aPresContext, reflowInput->mFloatManager, reflowInput, nullptr, aReflowInput.mLineLayout); lineLayout->SetSuppressLineWrap(true); lineLayouts.AppendElement(lineLayout); // Line number is useless for ruby text // XXX nullptr here may cause problem, see comments for // nsLineLayout::mBlockRI and nsLineLayout::AddFloat lineLayout->Init(nullptr, reflowInput->CalcLineHeight(), -1); reflowInput->mLineLayout = lineLayout; // Border and padding are suppressed on ruby text containers. // If the writing mode is vertical-rl, the horizontal position of // rt frames will be updated when reflowing this text container, // hence leave container size 0 here for now. lineLayout->BeginLineReflow(0, 0, reflowInput->ComputedISize(), NS_UNCONSTRAINEDSIZE, false, false, lineWM, nsSize(0, 0)); lineLayout->AttachRootFrameToBaseLineLayout(); } aReflowInput.mLineLayout->BeginSpan(this, &aReflowInput, 0, aReflowInput.AvailableISize(), &mBaseline); bool allowInitialLineBreak, allowLineBreak; GetIsLineBreakAllowed(this, aReflowInput.mLineLayout->LineIsBreakable(), &allowInitialLineBreak, &allowLineBreak); nscoord isize = 0; // Reflow columns excluding any span RubyReflowInput reflowInput = { allowInitialLineBreak, allowLineBreak && !hasSpan, textContainers, aReflowInput, reflowInputs }; isize = ReflowColumns(reflowInput, aStatus); DebugOnly<nscoord> lineSpanSize = aReflowInput.mLineLayout->EndSpan(this); aDesiredSize.ISize(lineWM) = isize; // When there are no frames inside the ruby base container, EndSpan // will return 0. However, in this case, the actual width of the // container could be non-zero because of non-empty ruby annotations. // XXX When bug 765861 gets fixed, this warning should be upgraded. NS_WARNING_ASSERTION( NS_INLINE_IS_BREAK(aStatus) || isize == lineSpanSize || mFrames.IsEmpty(), "bad isize"); // If there exists any span, the columns must either be completely // reflowed, or be not reflowed at all. MOZ_ASSERT(NS_INLINE_IS_BREAK_BEFORE(aStatus) || NS_FRAME_IS_COMPLETE(aStatus) || !hasSpan); if (!NS_INLINE_IS_BREAK_BEFORE(aStatus) && NS_FRAME_IS_COMPLETE(aStatus) && hasSpan) { // Reflow spans RubyReflowInput reflowInput = { false, false, textContainers, aReflowInput, reflowInputs }; nscoord spanISize = ReflowSpans(reflowInput); isize = std::max(isize, spanISize); } for (uint32_t i = 0; i < rtcCount; i++) { // It happens before the ruby text container is reflowed, and that // when it is reflowed, it will just use this size. nsRubyTextContainerFrame* textContainer = textContainers[i]; nsLineLayout* lineLayout = lineLayouts[i].get(); RubyUtils::ClearReservedISize(textContainer); nscoord rtcISize = lineLayout->GetCurrentICoord(); // Only span containers and containers with collapsed annotations // need reserving isize. For normal ruby text containers, their // children will be expanded properly. We only need to expand their // own size. if (!textContainer->IsSpanContainer()) { rtcISize = isize; } else if (isize > rtcISize) { RubyUtils::SetReservedISize(textContainer, isize - rtcISize); } lineLayout->VerticalAlignLine(); textContainer->SetISize(rtcISize); lineLayout->EndLineReflow(); } // Border and padding are suppressed on ruby base container, // create a fake borderPadding for setting BSize. WritingMode frameWM = aReflowInput.GetWritingMode(); LogicalMargin borderPadding(frameWM); nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, borderPadding, lineWM, frameWM); }