static void DebugCheckChildSize(nsIFrame* aChild, ReflowOutput& aMet) { WritingMode wm = aMet.GetWritingMode(); if ((aMet.ISize(wm) < 0) || (aMet.ISize(wm) > PROBABLY_TOO_LARGE)) { printf("WARNING: cell content %p has large inline size %d \n", static_cast<void*>(aChild), int32_t(aMet.ISize(wm))); } }
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()); }
/* virtual */ void nsRubyTextFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { // Even if we want to hide this frame, we have to reflow it first. // If we leave it dirty, changes to its content will never be // propagated to the ancestors, then it won't be displayed even if // the content is no longer the same, until next reflow triggered by // some other change. In general, we always reflow all the frames we // created. There might be other problems if we don't do that. nsRubyContentFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus); if (IsAutoHidden()) { // Reset the ISize. The BSize is not changed so that it won't // affect vertical positioning in unexpected way. WritingMode lineWM = aReflowInput.mLineLayout->GetWritingMode(); aDesiredSize.ISize(lineWM) = 0; aDesiredSize.SetOverflowAreasToDesiredBounds(); } }
/* 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 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 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); }
/* 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); }
/* 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); }