nscoord nsColumnSetFrame::GetAvailableContentHeight(const nsHTMLReflowState& aReflowState) { if (aReflowState.AvailableHeight() == NS_INTRINSICSIZE) { return NS_INTRINSICSIZE; } nsMargin bp = aReflowState.ComputedPhysicalBorderPadding(); bp.ApplySkipSides(GetSkipSides(&aReflowState)); bp.bottom = aReflowState.ComputedPhysicalBorderPadding().bottom; return std::max(0, aReflowState.AvailableHeight() - bp.TopBottom()); }
void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // printf("OuterFrame::Reflow %X (%d,%d) \n", this, aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d", aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); aStatus = NS_FRAME_COMPLETE; NS_ASSERTION(mContent->GetPrimaryFrame() == this, "Shouldn't happen"); // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed> nsLeafFrame::DoReflow(aPresContext, aDesiredSize, aReflowState, aStatus); // "offset" is the offset of our content area from our frame's // top-left corner. nsPoint offset = nsPoint(aReflowState.ComputedPhysicalBorderPadding().left, aReflowState.ComputedPhysicalBorderPadding().top); nsSize innerSize(aDesiredSize.Width(), aDesiredSize.Height()); innerSize.width -= aReflowState.ComputedPhysicalBorderPadding().LeftRight(); innerSize.height -= aReflowState.ComputedPhysicalBorderPadding().TopBottom(); if (mInnerView) { nsViewManager* vm = mInnerView->GetViewManager(); vm->MoveViewTo(mInnerView, offset.x, offset.y); vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), 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; } // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this, // aDesiredSize.Width(), aDesiredSize.Height()); 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, aReflowState, aDesiredSize); }
void nsFormControlFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsFormControlFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsFormControlFrame::Reflow: aMaxSize=%d,%d", aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); if (mState & NS_FRAME_FIRST_REFLOW) { RegUnRegAccessKey(static_cast<nsIFrame*>(this), true); } aStatus = NS_FRAME_COMPLETE; aDesiredSize.SetSize(aReflowState.GetWritingMode(), aReflowState.ComputedSizeWithBorderPadding()); if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) { float inflation = nsLayoutUtils::FontSizeInflationFor(this); aDesiredSize.Width() *= inflation; aDesiredSize.Height() *= inflation; } NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsFormControlFrame::Reflow: size=%d,%d", aDesiredSize.Width(), aDesiredSize.Height())); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); aDesiredSize.SetOverflowAreasToDesiredBounds(); FinishAndStoreOverflow(&aDesiredSize); }
void nsLeafFrame::SizeToAvailSize(const nsHTMLReflowState& aReflowState, nsHTMLReflowMetrics& aDesiredSize) { aDesiredSize.Width() = aReflowState.AvailableWidth(); // FRAME aDesiredSize.Height() = aReflowState.AvailableHeight(); aDesiredSize.SetOverflowAreasToDesiredBounds(); FinishAndStoreOverflow(&aDesiredSize); }
void nsRubyTextContainerFrame::ReflowRubyTextFrame( nsRubyTextFrame* rtFrame, nsIFrame* rbFrame, nscoord baseStart, nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState) { nsReflowStatus frameReflowStatus; nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags); mozilla::WritingMode lineWM = mLineLayout->GetWritingMode(); mozilla::LogicalSize availSize(lineWM, aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); nsHTMLReflowState childReflowState(aPresContext, aReflowState, rtFrame, availSize); // Determine the inline coordinate for the text frame by centering over // the corresponding base frame int baseWidth; if (rbFrame) { baseWidth = rbFrame->ISize(); // If this is the last ruby annotation, it gets paired with ALL remaining // ruby bases if (!rtFrame->GetNextSibling()) { rbFrame = rbFrame->GetNextSibling(); while (rbFrame) { baseWidth += rbFrame->ISize(); rbFrame = rbFrame->GetNextSibling(); } } } else { baseWidth = 0; } int baseCenter = baseStart + baseWidth / 2; // FIXME: Find a way to avoid using GetPrefISize here, potentially by moving // the frame after it has reflowed. nscoord ICoord = baseCenter - rtFrame->GetPrefISize(aReflowState.rendContext) / 2; if (ICoord > mLineLayout->GetCurrentICoord()) { mLineLayout->AdvanceICoord(ICoord - mLineLayout->GetCurrentICoord()); } bool pushedFrame; mLineLayout->ReflowFrame(rtFrame, frameReflowStatus, &metrics, pushedFrame); NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented"); mISize += metrics.ISize(lineWM); rtFrame->SetSize(nsSize(metrics.ISize(lineWM), metrics.BSize(lineWM))); FinishReflowChild(rtFrame, aPresContext, metrics, &childReflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW); }
/* virtual */ void nsRubyTextFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsRubyBaseFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); if (!aReflowState.mLineLayout) { NS_ASSERTION(aReflowState.mLineLayout, "No line layout provided to RubyTextFrame reflow method."); aStatus = NS_FRAME_COMPLETE; return; } WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode(); WritingMode frameWM = aReflowState.GetWritingMode(); LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding(); aStatus = NS_FRAME_COMPLETE; LogicalSize availSize(lineWM, aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); // Begin the span for the ruby text frame nscoord availableISize = aReflowState.AvailableISize(); NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE, "should no longer use available widths"); // Subtract off inline axis border+padding from availableISize availableISize -= borderPadding.IStartEnd(frameWM); aReflowState.mLineLayout->BeginSpan(this, &aReflowState, borderPadding.IStart(frameWM), availableISize, &mBaseline); for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) { nsReflowStatus frameReflowStatus; nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags); bool pushedFrame; aReflowState.mLineLayout->ReflowFrame(e.get(), frameReflowStatus, &metrics, pushedFrame); NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented"); e.get()->SetSize(LogicalSize(lineWM, metrics.ISize(lineWM), metrics.BSize(lineWM))); } aDesiredSize.ISize(lineWM) = aReflowState.mLineLayout->EndSpan(this); nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState, borderPadding, lineWM, frameWM); }
void nsScrollbarFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); // nsGfxScrollFrame may have told us to shrink to nothing. If so, make sure our // desired size agrees. if (aReflowState.AvailableWidth() == 0) { aDesiredSize.Width() = 0; } if (aReflowState.AvailableHeight() == 0) { aDesiredSize.Height() = 0; } }
nsresult nsLeafFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsLeafFrame"); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsLeafFrame::Reflow: aMaxSize=%d,%d", aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); DoReflow(aPresContext, aMetrics, aReflowState, aStatus); FinishAndStoreOverflow(&aMetrics); return NS_OK; }
void nsTableOuterFrame::OuterBeginReflowChild(nsPresContext* aPresContext, nsIFrame* aChildFrame, const nsHTMLReflowState& aOuterRS, void* aChildRSSpace, nscoord aAvailWidth) { // work around pixel rounding errors, round down to ensure we don't exceed the avail height in nscoord availHeight = aOuterRS.AvailableHeight(); if (NS_UNCONSTRAINEDSIZE != availHeight) { if (mCaptionFrames.FirstChild() == aChildFrame) { availHeight = NS_UNCONSTRAINEDSIZE; } else { nsMargin margin; GetChildMargin(aPresContext, aOuterRS, aChildFrame, aOuterRS.AvailableWidth(), margin); NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.top, "No unconstrainedsize arithmetic, please"); availHeight -= margin.top; NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.bottom, "No unconstrainedsize arithmetic, please"); availHeight -= margin.bottom; } } nsSize availSize(aAvailWidth, availHeight); // create and init the child reflow state, using placement new on // stack space allocated by the caller, so that the caller can destroy // it nsHTMLReflowState &childRS = * new (aChildRSSpace) nsHTMLReflowState(aPresContext, aOuterRS, aChildFrame, availSize, -1, -1, nsHTMLReflowState::CALLER_WILL_INIT); InitChildReflowState(*aPresContext, childRS); // see if we need to reset top-of-page due to a caption if (childRS.mFlags.mIsTopOfPage && mCaptionFrames.FirstChild() == aChildFrame) { uint8_t captionSide = GetCaptionSide(); if (captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM || captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE) { childRS.mFlags.mIsTopOfPage = false; } } }
// get the margin and padding data. nsHTMLReflowState doesn't handle the // case of auto margins void nsTableOuterFrame::GetChildMargin(nsPresContext* aPresContext, const nsHTMLReflowState& aOuterRS, nsIFrame* aChildFrame, nscoord aAvailWidth, nsMargin& aMargin) { // 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. nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, nsSize(aAvailWidth, aOuterRS.AvailableHeight()), -1, -1, nsHTMLReflowState::CALLER_WILL_INIT); InitChildReflowState(*aPresContext, childRS); aMargin = childRS.ComputedPhysicalMargin(); }
NS_IMETHODIMP nsScrollbarFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsresult rv = nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); NS_ENSURE_SUCCESS(rv, rv); // nsGfxScrollFrame may have told us to shrink to nothing. If so, make sure our // desired size agrees. if (aReflowState.AvailableWidth() == 0) { aDesiredSize.Width() = 0; } if (aReflowState.AvailableHeight() == 0) { aDesiredSize.Height() = 0; } return NS_OK; }
void nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsSVGOuterSVGFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsSVGOuterSVGFrame::Reflow: availSize=%d,%d", aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); aStatus = NS_FRAME_COMPLETE; aDesiredSize.Width() = aReflowState.ComputedWidth() + aReflowState.ComputedPhysicalBorderPadding().LeftRight(); aDesiredSize.Height() = aReflowState.ComputedHeight() + aReflowState.ComputedPhysicalBorderPadding().TopBottom(); NS_ASSERTION(!GetPrevInFlow(), "SVG can't currently be broken across pages."); SVGSVGElement *svgElem = static_cast<SVGSVGElement*>(mContent); nsSVGOuterSVGAnonChildFrame *anonKid = static_cast<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild()); if (mState & NS_FRAME_FIRST_REFLOW) { // Initialize svgElem->UpdateHasChildrenOnlyTransform(); } // If our SVG viewport has changed, update our content and notify. // http://www.w3.org/TR/SVG11/coords.html#ViewportSpace svgFloatSize newViewportSize( nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedWidth()), nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedHeight())); svgFloatSize oldViewportSize = svgElem->GetViewportSize(); uint32_t changeBits = 0; if (newViewportSize != oldViewportSize) { // When our viewport size changes, we may need to update the overflow rects // of our child frames. This is the case if: // // * We have a real/synthetic viewBox (a children-only transform), since // the viewBox transform will change as the viewport dimensions change. // // * We do not have a real/synthetic viewBox, but the last time we // reflowed (or the last time UpdateOverflow() was called) we did. // // We only handle the former case here, in which case we mark all our child // frames as dirty so that we reflow them below and update their overflow // rects. // // In the latter case, updating of overflow rects is handled for removal of // real viewBox (the viewBox attribute) in AttributeChanged. Synthetic // viewBox "removal" (e.g. a document references the same SVG via both an // <svg:image> and then as a CSS background image (a synthetic viewBox is // used when painting the former, but not when painting the latter)) is // handled in SVGSVGElement::FlushImageTransformInvalidation. // if (svgElem->HasViewBoxOrSyntheticViewBox()) { nsIFrame* anonChild = GetFirstPrincipalChild(); anonChild->AddStateBits(NS_FRAME_IS_DIRTY); for (nsIFrame* child = anonChild->GetFirstPrincipalChild(); child; child = child->GetNextSibling()) { child->AddStateBits(NS_FRAME_IS_DIRTY); } } changeBits |= COORD_CONTEXT_CHANGED; svgElem->SetViewportSize(newViewportSize); } if (mFullZoom != PresContext()->GetFullZoom()) { changeBits |= FULL_ZOOM_CHANGED; mFullZoom = PresContext()->GetFullZoom(); } if (changeBits) { NotifyViewportOrTransformChanged(changeBits); } mViewportInitialized = true; // Now that we've marked the necessary children as dirty, call // ReflowSVG() or ReflowSVGNonDisplayText() on them, depending // on whether we are non-display. mCallingReflowSVG = true; if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) { ReflowSVGNonDisplayText(this); } else { // Update the mRects and visual overflow rects of all our descendants, // including our anonymous wrapper kid: anonKid->AddStateBits(mState & NS_FRAME_IS_DIRTY); anonKid->ReflowSVG(); NS_ABORT_IF_FALSE(!anonKid->GetNextSibling(), "We should have one anonymous child frame wrapping our real children"); } mCallingReflowSVG = false; // Set our anonymous kid's offset from our border box: anonKid->SetPosition(GetContentRectRelativeToSelf().TopLeft()); // Including our size in our overflow rects regardless of the value of // 'background', 'border', etc. makes sure that we usually (when we clip to // our content area) don't have to keep changing our overflow rects as our // descendants move about (see perf comment below). Including our size in our // scrollable overflow rect also makes sure that we scroll if we're too big // for our viewport. // // <svg> never allows scrolling to anything outside its mRect (only panning), // so we must always keep our scrollable overflow set to our size. // // With regards to visual overflow, we always clip root-<svg> (see our // BuildDisplayList method) regardless of the value of the 'overflow' // property since that is per-spec, even for the initial 'visible' value. For // that reason there's no point in adding descendant visual overflow to our // own when this frame is for a root-<svg>. That said, there's also a very // good performance reason for us wanting to avoid doing so. If we did, then // the frame's overflow would often change as descendants that are partially // or fully outside its rect moved (think animation on/off screen), and that // would cause us to do a full NS_FRAME_IS_DIRTY reflow and repaint of the // entire document tree each such move (see bug 875175). // // So it's only non-root outer-<svg> that has the visual overflow of its // descendants added to its own. (Note that the default user-agent style // sheet makes 'hidden' the default value for :not(root(svg)), so usually // FinishAndStoreOverflow will still clip this back to the frame's rect.) // // WARNING!! Keep UpdateBounds below in sync with whatever we do for our // overflow rects here! (Again, see bug 875175.) // aDesiredSize.SetOverflowAreasToDesiredBounds(); if (!mIsRootContent) { aDesiredSize.mOverflowAreas.VisualOverflow().UnionRect( aDesiredSize.mOverflowAreas.VisualOverflow(), anonKid->GetVisualOverflowRect() + anonKid->GetPosition()); } FinishAndStoreOverflow(&aDesiredSize); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsSVGOuterSVGFrame::Reflow: size=%d,%d", aDesiredSize.Width(), aDesiredSize.Height())); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
nsresult nsFirstLetterFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aReflowStatus) { DO_GLOBAL_REFLOW_COUNT("nsFirstLetterFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aReflowStatus); nsresult rv = NS_OK; // Grab overflow list DrainOverflowFrames(aPresContext); nsIFrame* kid = mFrames.FirstChild(); // Setup reflow state for our child nsSize availSize(aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); const nsMargin& bp = aReflowState.ComputedPhysicalBorderPadding(); nscoord lr = bp.left + bp.right; nscoord tb = bp.top + bp.bottom; NS_ASSERTION(availSize.width != NS_UNCONSTRAINEDSIZE, "should no longer use unconstrained widths"); availSize.width -= lr; if (NS_UNCONSTRAINEDSIZE != availSize.height) { availSize.height -= tb; } // Reflow the child if (!aReflowState.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. nsHTMLReflowState rs(aPresContext, aReflowState, kid, availSize); nsLineLayout ll(aPresContext, nullptr, &aReflowState, nullptr); ll.BeginLineReflow(bp.left, bp.top, availSize.width, NS_UNCONSTRAINEDSIZE, false, true, ll.LineContainerFrame()->GetWritingMode(kid), aReflowState.AvailableWidth()); rs.mLineLayout = ≪ ll.SetInFirstLetter(true); ll.SetFirstLetterStyleOK(true); kid->WillReflow(aPresContext); kid->Reflow(aPresContext, aMetrics, 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 = aMetrics.TopAscent(); } else { // Pretend we are a span and reflow the child frame nsLineLayout* ll = aReflowState.mLineLayout; bool pushedFrame; ll->SetInFirstLetter( mStyleContext->GetPseudo() == nsCSSPseudoElements::firstLetter); ll->BeginSpan(this, &aReflowState, bp.left, availSize.width, &mBaseline); ll->ReflowFrame(kid, aReflowStatus, &aMetrics, pushedFrame); ll->EndSpan(this); ll->SetInFirstLetter(false); } // Place and size the child and update the output metrics kid->SetRect(nsRect(bp.left, bp.top, aMetrics.Width(), aMetrics.Height())); kid->FinishAndStoreOverflow(&aMetrics); kid->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED); aMetrics.Width() += lr; aMetrics.Height() += tb; aMetrics.SetTopAscent(aMetrics.TopAscent() + bp.top); // 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); 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 (aReflowState.mLineLayout) { aReflowState.mLineLayout->SetFirstLetterStyleOK(false); } nsIFrame* kidNextInFlow = kid->GetNextInFlow(); if (kidNextInFlow) { // Remove all of the childs next-in-flows static_cast<nsContainerFrame*>(kidNextInFlow->GetParent()) ->DeleteNextInFlowChild(kidNextInFlow, true); } } else { // Create a continuation for the child frame if it doesn't already // have one. if (!IsFloating()) { nsIFrame* nextInFlow; rv = CreateNextInFlow(kid, nextInFlow); if (NS_FAILED(rv)) { return rv; } // 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; rv = CreateContinuationForFloatingParent(aPresContext, kid, &continuation, true); } } } FinishAndStoreOverflow(&aMetrics); NS_FRAME_SET_TRUNCATION(aReflowStatus, aReflowState, aMetrics); return rv; }
NS_METHOD nsTableOuterFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aOuterRS, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame"); DISPLAY_REFLOW(aPresContext, this, aOuterRS, aDesiredSize, aStatus); nsresult rv = NS_OK; uint8_t captionSide = GetCaptionSide(); // Initialize out parameters aDesiredSize.Width() = aDesiredSize.Height() = 0; aStatus = NS_FRAME_COMPLETE; if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // Set up our kids. They're already present, on an overflow list, // or there are none so we'll create them now MoveOverflowToChildList(); } // Use longs to get more-aligned space. #define LONGS_IN_HTMLRS \ ((sizeof(nsHTMLReflowState) + sizeof(long) - 1) / sizeof(long)) long captionRSSpace[LONGS_IN_HTMLRS]; nsHTMLReflowState *captionRS = static_cast<nsHTMLReflowState*>((void*)captionRSSpace); long innerRSSpace[LONGS_IN_HTMLRS]; nsHTMLReflowState *innerRS = static_cast<nsHTMLReflowState*>((void*) innerRSSpace); nsRect origInnerRect = InnerTableFrame()->GetRect(); nsRect origInnerVisualOverflow = InnerTableFrame()->GetVisualOverflowRect(); bool innerFirstReflow = (InnerTableFrame()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; nsRect origCaptionRect; nsRect origCaptionVisualOverflow; bool captionFirstReflow; if (mCaptionFrames.NotEmpty()) { origCaptionRect = mCaptionFrames.FirstChild()->GetRect(); origCaptionVisualOverflow = mCaptionFrames.FirstChild()->GetVisualOverflowRect(); captionFirstReflow = (mCaptionFrames.FirstChild()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; } // ComputeAutoSize has to match this logic. if (captionSide == NO_SIDE) { // We don't have a caption. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, aOuterRS.ComputedWidth()); } else if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT || captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) { // nsTableCaptionFrame::ComputeAutoSize takes care of making side // captions small. Compute the caption's size first, and tell the // table to fit in what's left. OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS, captionRSSpace, aOuterRS.ComputedWidth()); nscoord innerAvailWidth = aOuterRS.ComputedWidth() - (captionRS->ComputedWidth() + captionRS->ComputedPhysicalMargin().LeftRight() + captionRS->ComputedPhysicalBorderPadding().LeftRight()); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, innerAvailWidth); } else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP || captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) { // Compute the table's size first, and then prevent the caption from // being wider unless it has to be. // // Note that CSS 2.1 (but not 2.0) says: // The width of the anonymous box is the border-edge width of the // table box inside it // We don't actually make our anonymous box that width (if we did, // it would break 'auto' margins), but this effectively does that. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, aOuterRS.ComputedWidth()); // It's good that CSS 2.1 says not to include margins, since we // can't, since they already been converted so they exactly // fill the available width (ignoring the margin on one side if // neither are auto). (We take advantage of that later when we call // GetCaptionOrigin, though.) nscoord innerBorderWidth = innerRS->ComputedWidth() + innerRS->ComputedPhysicalBorderPadding().LeftRight(); OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS, captionRSSpace, innerBorderWidth); } else { NS_ASSERTION(captionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE || captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE, "unexpected caption-side"); // Size the table and the caption independently. OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS, captionRSSpace, aOuterRS.ComputedWidth()); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, aOuterRS.ComputedWidth()); } // First reflow the caption. nsHTMLReflowMetrics captionMet(captionRS->GetWritingMode()); nsSize captionSize; nsMargin captionMargin; if (mCaptionFrames.NotEmpty()) { nsReflowStatus capStatus; // don't let the caption cause incomplete rv = OuterDoReflowChild(aPresContext, mCaptionFrames.FirstChild(), *captionRS, captionMet, capStatus); if (NS_FAILED(rv)) return rv; captionSize.width = captionMet.Width(); captionSize.height = captionMet.Height(); captionMargin = captionRS->ComputedPhysicalMargin(); // Now that we know the height of the caption, reduce the available height // for the table frame if we are height constrained and the caption is above // or below the inner table. if (NS_UNCONSTRAINEDSIZE != aOuterRS.AvailableHeight()) { nscoord captionHeight = 0; switch (captionSide) { case NS_STYLE_CAPTION_SIDE_TOP: case NS_STYLE_CAPTION_SIDE_BOTTOM: case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE: case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE: { captionHeight = captionSize.height + captionMargin.TopBottom(); break; } } innerRS->AvailableHeight() = std::max(0, innerRS->AvailableHeight() - captionHeight); } } else { captionSize.SizeTo(0,0); captionMargin.SizeTo(0,0,0,0); } // Then, now that we know how much to reduce the width of the inner // table to account for side captions, reflow the inner table. nsHTMLReflowMetrics innerMet(innerRS->GetWritingMode()); rv = OuterDoReflowChild(aPresContext, InnerTableFrame(), *innerRS, innerMet, aStatus); if (NS_FAILED(rv)) return rv; nsSize innerSize; innerSize.width = innerMet.Width(); innerSize.height = innerMet.Height(); nsMargin innerMargin = innerRS->ComputedPhysicalMargin(); nsSize containSize = GetContainingBlockSize(aOuterRS); // Now that we've reflowed both we can place them. // XXXldb Most of the input variables here are now uninitialized! // XXX Need to recompute inner table's auto margins for the case of side // captions. (Caption's are broken too, but that should be fixed earlier.) if (mCaptionFrames.NotEmpty()) { nsPoint captionOrigin; GetCaptionOrigin(captionSide, containSize, innerSize, innerMargin, captionSize, captionMargin, captionOrigin); FinishReflowChild(mCaptionFrames.FirstChild(), aPresContext, captionMet, captionRS, captionOrigin.x, captionOrigin.y, 0); captionRS->~nsHTMLReflowState(); } // XXX If the height is constrained then we need to check whether // everything still fits... nsPoint innerOrigin; GetInnerOrigin(captionSide, containSize, captionSize, captionMargin, innerSize, innerMargin, innerOrigin); FinishReflowChild(InnerTableFrame(), aPresContext, innerMet, innerRS, innerOrigin.x, innerOrigin.y, 0); innerRS->~nsHTMLReflowState(); nsTableFrame::InvalidateTableFrame(InnerTableFrame(), origInnerRect, origInnerVisualOverflow, innerFirstReflow); if (mCaptionFrames.NotEmpty()) { nsTableFrame::InvalidateTableFrame(mCaptionFrames.FirstChild(), origCaptionRect, origCaptionVisualOverflow, captionFirstReflow); } UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, captionMargin); if (GetPrevInFlow()) { ReflowOverflowContainerChildren(aPresContext, aOuterRS, aDesiredSize.mOverflowAreas, 0, aStatus); } FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aOuterRS, aStatus); // Return our desired rect NS_FRAME_SET_TRUNCATION(aStatus, aOuterRS, aDesiredSize); return rv; }
void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d", aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); NS_ASSERTION(aReflowState.ComputedWidth() != NS_UNCONSTRAINEDSIZE, "Shouldn't have unconstrained stuff here " "thanks to the rules of reflow"); NS_ASSERTION(NS_INTRINSICSIZE != aReflowState.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(aReflowState.GetWritingMode(), aReflowState.ComputedSizeWithBorderPadding()); // "offset" is the offset of our content area from our frame's // top-left corner. nsPoint offset = nsPoint(aReflowState.ComputedPhysicalBorderPadding().left, aReflowState.ComputedPhysicalBorderPadding().top); if (mInnerView) { const nsMargin& bp = aReflowState.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, aReflowState, aDesiredSize); }
void nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame, nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, const nsRect& aContainingBlock, bool aConstrainHeight, nsIFrame* aKidFrame, nsReflowStatus& aStatus, nsOverflowAreas* aOverflowAreas) { #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent); printf("abs pos "); if (aKidFrame) { nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); } char width[16]; char height[16]; PrettyUC(aReflowState.AvailableWidth(), width); PrettyUC(aReflowState.AvailableHeight(), height); printf(" a=%s,%s ", width, height); PrettyUC(aReflowState.ComputedWidth(), width); PrettyUC(aReflowState.ComputedHeight(), height); printf("c=%s,%s \n", width, height); } AutoNoisyIndenter indent(nsBlockFrame::gNoisy); #endif // DEBUG WritingMode wm = aKidFrame->GetWritingMode(); nscoord availISize = LogicalSize(wm, aContainingBlock.Size()).ISize(wm); if (availISize == -1) { NS_ASSERTION(aReflowState.ComputedSize(wm).ISize(wm) != NS_UNCONSTRAINEDSIZE, "Must have a useful inline-size _somewhere_"); availISize = aReflowState.ComputedSizeWithPadding(wm).ISize(wm); } nsHTMLReflowMetrics kidDesiredSize(aReflowState); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame, LogicalSize(wm, availISize, NS_UNCONSTRAINEDSIZE), aContainingBlock.width, aContainingBlock.height); // Get the border values const nsMargin& border = aReflowState.mStyleBorder->GetComputedBorder(); bool constrainHeight = (aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE) && aConstrainHeight // 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->GetRect().y <= aReflowState.AvailableHeight()); // 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 (constrainHeight) { kidReflowState.AvailableHeight() = aReflowState.AvailableHeight() - border.top - kidReflowState.ComputedPhysicalMargin().top; if (NS_AUTOOFFSET != kidReflowState.ComputedPhysicalOffsets().top) kidReflowState.AvailableHeight() -= kidReflowState.ComputedPhysicalOffsets().top; } // Do the reflow aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); // If we're solving for 'left' or 'top', then compute it now that we know the // width/height if ((NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().left) || (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().top)) { nscoord aContainingBlockWidth = aContainingBlock.width; nscoord aContainingBlockHeight = aContainingBlock.height; if (-1 == aContainingBlockWidth) { // Get the containing block width/height kidReflowState.ComputeContainingBlockRectangle(aPresContext, &aReflowState, aContainingBlockWidth, aContainingBlockHeight); } if (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().left) { NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.ComputedPhysicalOffsets().right, "Can't solve for both left and right"); kidReflowState.ComputedPhysicalOffsets().left = aContainingBlockWidth - kidReflowState.ComputedPhysicalOffsets().right - kidReflowState.ComputedPhysicalMargin().right - kidDesiredSize.Width() - kidReflowState.ComputedPhysicalMargin().left; } if (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().top) { kidReflowState.ComputedPhysicalOffsets().top = aContainingBlockHeight - kidReflowState.ComputedPhysicalOffsets().bottom - kidReflowState.ComputedPhysicalMargin().bottom - kidDesiredSize.Height() - kidReflowState.ComputedPhysicalMargin().top; } } // Position the child relative to our padding edge nsRect rect(border.left + kidReflowState.ComputedPhysicalOffsets().left + kidReflowState.ComputedPhysicalMargin().left, border.top + kidReflowState.ComputedPhysicalOffsets().top + kidReflowState.ComputedPhysicalMargin().top, kidDesiredSize.Width(), kidDesiredSize.Height()); // 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. if (aContainingBlock.TopLeft() != nsPoint(0, 0)) { if (!(kidReflowState.mStylePosition->mOffset.GetLeftUnit() == eStyleUnit_Auto && kidReflowState.mStylePosition->mOffset.GetRightUnit() == eStyleUnit_Auto)) { rect.x += aContainingBlock.x; } if (!(kidReflowState.mStylePosition->mOffset.GetTopUnit() == eStyleUnit_Auto && kidReflowState.mStylePosition->mOffset.GetBottomUnit() == eStyleUnit_Auto)) { rect.y += aContainingBlock.y; } } aKidFrame->SetRect(rect); 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, &kidReflowState, nsDidReflowStatus::FINISHED); #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1); printf("abs pos "); if (aKidFrame) { nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); } printf("%p rect=%d,%d,%d,%d\n", static_cast<void*>(aKidFrame), rect.x, rect.y, rect.width, rect.height); } #endif if (aOverflowAreas) { aOverflowAreas->UnionWith(kidDesiredSize.mOverflowAreas + rect.TopLeft()); } }
bool nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus, const ReflowConfig& aConfig, bool aUnboundedLastColumn, nsCollapsingMargin* aBottomMarginCarriedOut, ColumnBalanceData& aColData) { aColData.Reset(); bool allFit = true; bool RTL = StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; bool shrinkingHeightOnly = !NS_SUBTREE_DIRTY(this) && mLastBalanceHeight > aConfig.mColMaxHeight; #ifdef DEBUG_roc printf("*** Doing column reflow pass: mLastBalanceHeight=%d, mColMaxHeight=%d, RTL=%d\n, mBalanceColCount=%d, mColWidth=%d, mColGap=%d\n", mLastBalanceHeight, aConfig.mColMaxHeight, RTL, aConfig.mBalanceColCount, aConfig.mColWidth, aConfig.mColGap); #endif DrainOverflowColumns(); const bool colHeightChanged = mLastBalanceHeight != aConfig.mColMaxHeight; if (colHeightChanged) { mLastBalanceHeight = aConfig.mColMaxHeight; // XXX Seems like this could fire if incremental reflow pushed the column set // down so we reflow incrementally with a different available height. // We need a way to do an incremental reflow and be sure availableHeight // changes are taken account of! Right now I think block frames with absolute // children might exit early. //NS_ASSERTION(aKidReason != eReflowReason_Incremental, // "incremental reflow should not have changed the balance height"); } // get our border and padding nsMargin borderPadding = aReflowState.ComputedPhysicalBorderPadding(); borderPadding.ApplySkipSides(GetSkipSides(&aReflowState)); nsRect contentRect(0, 0, 0, 0); nsOverflowAreas overflowRects; nsIFrame* child = mFrames.FirstChild(); nsPoint childOrigin = nsPoint(borderPadding.left, borderPadding.top); // For RTL, figure out where the last column's left edge should be. Since the // columns might not fill the frame exactly, we need to account for the // slop. Otherwise we'll waste time moving the columns by some tiny // amount unnecessarily. if (RTL) { nscoord availWidth = aReflowState.AvailableWidth(); if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) { availWidth = aReflowState.ComputedWidth(); } if (availWidth != NS_INTRINSICSIZE) { childOrigin.x += availWidth - aConfig.mColWidth; #ifdef DEBUG_roc printf("*** childOrigin.x = %d\n", childOrigin.x); #endif } } int columnCount = 0; int contentBEnd = 0; bool reflowNext = false; while (child) { // Try to skip reflowing the child. We can't skip if the child is dirty. We also can't // skip if the next column is dirty, because the next column's first line(s) // might be pullable back to this column. We can't skip if it's the last child // because we need to obtain the bottom margin. We can't skip // if this is the last column and we're supposed to assign unbounded // height to it, because that could change the available height from // the last time we reflowed it and we should try to pull all the // content from its next sibling. (Note that it might be the last // column, but not be the last child because the desired number of columns // has changed.) bool skipIncremental = !aReflowState.ShouldReflowAllKids() && !NS_SUBTREE_DIRTY(child) && child->GetNextSibling() && !(aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) && !NS_SUBTREE_DIRTY(child->GetNextSibling()); // If we need to pull up content from the prev-in-flow then this is not just // a height shrink. The prev in flow will have set the dirty bit. // Check the overflow rect YMost instead of just the child's content height. The child // may have overflowing content that cares about the available height boundary. // (It may also have overflowing content that doesn't care about the available height // boundary, but if so, too bad, this optimization is defeated.) // We want scrollable overflow here since this is a calculation that // affects layout. bool skipResizeHeightShrink = shrinkingHeightOnly && child->GetScrollableOverflowRect().YMost() <= aConfig.mColMaxHeight; nscoord childContentBEnd = 0; WritingMode wm = child->GetWritingMode(); if (!reflowNext && (skipIncremental || skipResizeHeightShrink)) { // This child does not need to be reflowed, but we may need to move it MoveChildTo(this, child, childOrigin); // If this is the last frame then make sure we get the right status nsIFrame* kidNext = child->GetNextSibling(); if (kidNext) { aStatus = (kidNext->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) ? NS_FRAME_OVERFLOW_INCOMPLETE : NS_FRAME_NOT_COMPLETE; } else { aStatus = mLastFrameStatus; } childContentBEnd = nsLayoutUtils::CalculateContentBEnd(wm, child); #ifdef DEBUG_roc printf("*** Skipping child #%d %p (incremental %d, resize height shrink %d): status = %d\n", columnCount, (void*)child, skipIncremental, skipResizeHeightShrink, aStatus); #endif } else { nsSize physicalSize(aConfig.mColWidth, aConfig.mColMaxHeight); if (aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) { physicalSize.height = GetAvailableContentHeight(aReflowState); } LogicalSize availSize(wm, physicalSize); LogicalSize computedSize = aReflowState.ComputedSize(wm); if (reflowNext) child->AddStateBits(NS_FRAME_IS_DIRTY); nsHTMLReflowState kidReflowState(PresContext(), aReflowState, child, availSize, availSize.ISize(wm), computedSize.BSize(wm)); kidReflowState.mFlags.mIsTopOfPage = true; kidReflowState.mFlags.mTableIsSplittable = false; kidReflowState.mFlags.mIsColumnBalancing = aConfig.mBalanceColCount < INT32_MAX; // We need to reflow any float placeholders, even if our column height // hasn't changed. kidReflowState.mFlags.mMustReflowPlaceholders = !colHeightChanged; #ifdef DEBUG_roc printf("*** Reflowing child #%d %p: availHeight=%d\n", columnCount, (void*)child,availSize.BSize(wm)); #endif // Note if the column's next in flow is not being changed by this incremental reflow. // This may allow the current column to avoid trying to pull lines from the next column. if (child->GetNextSibling() && !(GetStateBits() & NS_FRAME_IS_DIRTY) && !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY)) { kidReflowState.mFlags.mNextInFlowUntouched = true; } nsHTMLReflowMetrics kidDesiredSize(wm, aDesiredSize.mFlags); // XXX it would be cool to consult the float manager for the // previous block to figure out the region of floats from the // previous column that extend into this column, and subtract // that region from the new float manager. So you could stick a // really big float in the first column and text in following // columns would flow around it. // Reflow the frame ReflowChild(child, PresContext(), kidDesiredSize, kidReflowState, childOrigin.x + kidReflowState.ComputedPhysicalMargin().left, childOrigin.y + kidReflowState.ComputedPhysicalMargin().top, 0, aStatus); reflowNext = (aStatus & NS_FRAME_REFLOW_NEXTINFLOW) != 0; #ifdef DEBUG_roc printf("*** Reflowed child #%d %p: status = %d, desiredSize=%d,%d CarriedOutBottomMargin=%d\n", columnCount, (void*)child, aStatus, kidDesiredSize.Width(), kidDesiredSize.Height(), kidDesiredSize.mCarriedOutBEndMargin.get()); #endif NS_FRAME_TRACE_REFLOW_OUT("Column::Reflow", aStatus); *aBottomMarginCarriedOut = kidDesiredSize.mCarriedOutBEndMargin; FinishReflowChild(child, PresContext(), kidDesiredSize, &kidReflowState, childOrigin.x, childOrigin.y, 0); childContentBEnd = nsLayoutUtils::CalculateContentBEnd(wm, child); if (childContentBEnd > aConfig.mColMaxHeight) { allFit = false; } if (childContentBEnd > availSize.BSize(wm)) { aColData.mMaxOverflowingHeight = std::max(childContentBEnd, aColData.mMaxOverflowingHeight); } } contentRect.UnionRect(contentRect, child->GetRect()); ConsiderChildOverflow(overflowRects, child); contentBEnd = std::max(contentBEnd, childContentBEnd); aColData.mLastHeight = childContentBEnd; aColData.mSumHeight += childContentBEnd; // Build a continuation column if necessary nsIFrame* kidNextInFlow = child->GetNextInFlow(); if (NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)) { NS_ASSERTION(!kidNextInFlow, "next in flow should have been deleted"); child = nullptr; break; } else { ++columnCount; // Make sure that the column has a next-in-flow. If not, we must // create one to hold the overflowing stuff, even if we're just // going to put it on our overflow list and let *our* // next in flow handle it. if (!kidNextInFlow) { NS_ASSERTION(aStatus & NS_FRAME_REFLOW_NEXTINFLOW, "We have to create a continuation, but the block doesn't want us to reflow it?"); // We need to create a continuing column nsresult rv = CreateNextInFlow(child, kidNextInFlow); if (NS_FAILED(rv)) { NS_NOTREACHED("Couldn't create continuation"); child = nullptr; break; } } // Make sure we reflow a next-in-flow when it switches between being // normal or overflow container if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { if (!(kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) { aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; reflowNext = true; kidNextInFlow->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); } } else if (kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) { aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; reflowNext = true; kidNextInFlow->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); } if ((contentBEnd > aReflowState.ComputedMaxBSize() || contentBEnd > aReflowState.ComputedBSize()) && aConfig.mBalanceColCount < INT32_MAX) { // We overflowed vertically, but have not exceeded the number of // columns. We're going to go into overflow columns now, so balancing // no longer applies. aColData.mHasExcessHeight = true; } if (columnCount >= aConfig.mBalanceColCount) { // No more columns allowed here. Stop. aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; kidNextInFlow->AddStateBits(NS_FRAME_IS_DIRTY); // Move any of our leftover columns to our overflow list. Our // next-in-flow will eventually pick them up. const nsFrameList& continuationColumns = mFrames.RemoveFramesAfter(child); if (continuationColumns.NotEmpty()) { SetOverflowFrames(continuationColumns); } child = nullptr; break; } } if (PresContext()->HasPendingInterrupt()) { // Stop the loop now while |child| still points to the frame that bailed // out. We could keep going here and condition a bunch of the code in // this loop on whether there's an interrupt, or even just keep going and // trying to reflow the blocks (even though we know they'll interrupt // right after their first line), but stopping now is conceptually the // simplest (and probably fastest) thing. break; } // Advance to the next column child = child->GetNextSibling(); if (child) { if (!RTL) { childOrigin.x += aConfig.mColWidth + aConfig.mColGap; } else { childOrigin.x -= aConfig.mColWidth + aConfig.mColGap; } #ifdef DEBUG_roc printf("*** NEXT CHILD ORIGIN.x = %d\n", childOrigin.x); #endif } } if (PresContext()->CheckForInterrupt(this) && (GetStateBits() & NS_FRAME_IS_DIRTY)) { // Mark all our kids starting with |child| dirty // Note that this is a CheckForInterrupt call, not a HasPendingInterrupt, // because we might have interrupted while reflowing |child|, and since // we're about to add a dirty bit to |child| we need to make sure that // |this| is scheduled to have dirty bits marked on it and its ancestors. // Otherwise, when we go to mark dirty bits on |child|'s ancestors we'll // bail out immediately, since it'll already have a dirty bit. for (; child; child = child->GetNextSibling()) { child->AddStateBits(NS_FRAME_IS_DIRTY); } } aColData.mMaxHeight = contentBEnd; contentRect.height = std::max(contentRect.height, contentBEnd); mLastFrameStatus = aStatus; // contentRect included the borderPadding.left,borderPadding.top of the child rects contentRect -= nsPoint(borderPadding.left, borderPadding.top); WritingMode wm = aReflowState.GetWritingMode(); LogicalSize contentSize(wm, nsSize(contentRect.XMost(), contentRect.YMost())); // Apply computed and min/max values // (aConfig members need to be converted from Width/Height to ISize/BSize) if (aConfig.mComputedHeight != NS_INTRINSICSIZE) { if (aReflowState.AvailableHeight() != NS_INTRINSICSIZE) { contentSize.BSize(wm) = std::min(contentSize.BSize(wm), aConfig.mComputedHeight); } else { contentSize.BSize(wm) = aConfig.mComputedHeight; } } else { // We add the "consumed" height back in so that we're applying // constraints to the correct height value, then subtract it again // after we've finished with the min/max calculation. This prevents us from // having a last continuation that is smaller than the min height. but which // has prev-in-flows, trigger a larger height than actually required. contentSize.BSize(wm) = aReflowState.ApplyMinMaxHeight(contentSize.BSize(wm), aConfig.mConsumedHeight); } if (aReflowState.ComputedISize() != NS_INTRINSICSIZE) { contentSize.ISize(wm) = aReflowState.ComputedISize(); } else { contentSize.ISize(wm) = aReflowState.ApplyMinMaxWidth(contentSize.ISize(wm)); } LogicalMargin bp(wm, borderPadding); contentSize.ISize(wm) += bp.IStartEnd(wm); contentSize.BSize(wm) += bp.BStartEnd(wm); aDesiredSize.SetSize(wm, contentSize); aDesiredSize.mOverflowAreas = overflowRects; aDesiredSize.UnionOverflowAreasWithDesiredBounds(); #ifdef DEBUG_roc printf("*** DONE PASS feasible=%d\n", allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)); #endif return allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus); }
NS_IMETHODIMP nsCanvasFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow"); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; nsCanvasFrame* prevCanvasFrame = static_cast<nsCanvasFrame*> (GetPrevInFlow()); if (prevCanvasFrame) { AutoFrameListPtr overflow(aPresContext, prevCanvasFrame->StealOverflowFrames()); if (overflow) { NS_ASSERTION(overflow->OnlyChild(), "must have doc root as canvas frame's only child"); nsContainerFrame::ReparentFrameViewList(aPresContext, *overflow, prevCanvasFrame, this); // Prepend overflow to the our child list. There may already be // children placeholders for fixed-pos elements, which don't get // reflowed but must not be lost until the canvas frame is destroyed. mFrames.InsertFrames(this, nullptr, *overflow); } } // 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(aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); // Reflow our one and only normal child frame. It's either the root // element's frame or a placeholder for that frame, if the root element // is abs-pos or fixed-pos. We may have additional children which // are placeholders for continuations of fixed-pos content, but those // don't need to be reflowed. The normal child is always comes before // the fixed-pos placeholders, because we insert it at the start // of the child list, above. nsHTMLReflowMetrics kidDesiredSize(aReflowState.GetWritingMode()); if (mFrames.IsEmpty()) { // We have no child frame, so return an empty size aDesiredSize.Width() = aDesiredSize.Height() = 0; } else { nsIFrame* kidFrame = mFrames.FirstChild(); bool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0; nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, nsSize(aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); if (aReflowState.mFlags.mVResize && (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) { // Tell our kid it's being vertically resized too. Bit of a // hack for framesets. kidReflowState.mFlags.mVResize = true; } nsPoint kidPt(kidReflowState.ComputedPhysicalMargin().left, kidReflowState.ComputedPhysicalMargin().top); kidReflowState.ApplyRelativePositioning(&kidPt); // Reflow the frame ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, kidPt.x, kidPt.y, 0, aStatus); // Complete the reflow and position and size the child frame FinishReflowChild(kidFrame, aPresContext, &kidReflowState, kidDesiredSize, kidPt.x, kidPt.y, 0); if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) { nsIFrame* nextFrame = kidFrame->GetNextInFlow(); NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW, "If it's incomplete and has no nif yet, it must flag a nif reflow."); if (!nextFrame) { nextFrame = aPresContext->PresShell()->FrameConstructor()-> CreateContinuingFrame(aPresContext, kidFrame, this); SetOverflowFrames(aPresContext, nsFrameList(nextFrame, nextFrame)); // Root overflow containers will be normal children of // the canvas frame, but that's ok because there // aren't any other frames we need to isolate them from // during reflow. } if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); } } // If the child frame was just inserted, then we're responsible for making sure // it repaints if (kidDirty) { // But we have a new child, which will affect our background, so // invalidate our whole rect. // Note: Even though we request to be sized to our child's size, our // scroll frame ensures that we are always the size of the viewport. // Also note: GetPosition() on a CanvasFrame is always going to return // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect() // could also include overflow to our top and left (out of the viewport) // which doesn't need to be painted. nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame(); viewport->InvalidateFrame(); } // Return our desired size. Normally it's what we're told, but // sometimes we can be given an unconstrained height (when a window // is sizing-to-content), and we should compute our desired height. aDesiredSize.Width() = aReflowState.ComputedWidth(); if (aReflowState.ComputedHeight() == NS_UNCONSTRAINEDSIZE) { aDesiredSize.Height() = kidFrame->GetRect().height + kidReflowState.ComputedPhysicalMargin().TopBottom(); } else { aDesiredSize.Height() = aReflowState.ComputedHeight(); } aDesiredSize.SetOverflowAreasToDesiredBounds(); aDesiredSize.mOverflowAreas.UnionWith( kidDesiredSize.mOverflowAreas + kidPt); } if (prevCanvasFrame) { ReflowOverflowContainerChildren(aPresContext, aReflowState, aDesiredSize.mOverflowAreas, 0, aStatus); } FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); NS_FRAME_TRACE_REFLOW_OUT("nsCanvasFrame::Reflow", aStatus); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
nsresult nsBlockReflowContext::ReflowBlock(const nsRect& aSpace, bool aApplyTopMargin, nsCollapsingMargin& aPrevMargin, nscoord aClearance, bool aIsAdjacentWithTop, nsLineBox* aLine, nsHTMLReflowState& aFrameRS, nsReflowStatus& aFrameReflowStatus, nsBlockReflowState& aState) { nsresult rv = NS_OK; mFrame = aFrameRS.frame; mSpace = aSpace; if (!aIsAdjacentWithTop) { aFrameRS.mFlags.mIsTopOfPage = false; // make sure this is cleared } if (aApplyTopMargin) { mTopMargin = aPrevMargin; #ifdef NOISY_VERTICAL_MARGINS nsFrame::ListTag(stdout, mOuterReflowState.frame); printf(": reflowing "); nsFrame::ListTag(stdout, mFrame); printf(" margin => %d, clearance => %d\n", mTopMargin.get(), aClearance); #endif // Adjust the available height if its constrained so that the // child frame doesn't think it can reflow into its margin area. if (NS_UNCONSTRAINEDSIZE != aFrameRS.AvailableHeight()) { aFrameRS.AvailableHeight() -= mTopMargin.get() + aClearance; } } nscoord tx = 0, ty = 0; // The values of x and y do not matter for floats, so don't bother calculating // them. Floats are guaranteed to have their own float manager, so tx and ty // don't matter. mX and mY don't matter becacuse they are only used in // PlaceBlock, which is not used for floats. if (aLine) { // Compute x/y coordinate where reflow will begin. Use the rules // from 10.3.3 to determine what to apply. At this point in the // reflow auto left/right margins will have a zero value. mX = tx = mSpace.x + aFrameRS.ComputedPhysicalMargin().left; mY = ty = mSpace.y + mTopMargin.get() + aClearance; if ((mFrame->GetStateBits() & NS_BLOCK_FLOAT_MGR) == 0) aFrameRS.mBlockDelta = mOuterReflowState.mBlockDelta + ty - aLine->mBounds.y; } // Let frame know that we are reflowing it mFrame->WillReflow(mPresContext); #ifdef DEBUG mMetrics.Width() = nscoord(0xdeadbeef); mMetrics.Height() = nscoord(0xdeadbeef); #endif mOuterReflowState.mFloatManager->Translate(tx, ty); rv = mFrame->Reflow(mPresContext, mMetrics, aFrameRS, aFrameReflowStatus); mOuterReflowState.mFloatManager->Translate(-tx, -ty); #ifdef DEBUG if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) { if (CRAZY_SIZE(mMetrics.Width()) || CRAZY_SIZE(mMetrics.Height())) { printf("nsBlockReflowContext: "); nsFrame::ListTag(stdout, mFrame); printf(" metrics=%d,%d!\n", mMetrics.Width(), mMetrics.Height()); } if ((mMetrics.Width() == nscoord(0xdeadbeef)) || (mMetrics.Height() == nscoord(0xdeadbeef))) { printf("nsBlockReflowContext: "); nsFrame::ListTag(stdout, mFrame); printf(" didn't set w/h %d,%d!\n", mMetrics.Width(), mMetrics.Height()); } } #endif if (!mFrame->HasOverflowAreas()) { mMetrics.SetOverflowAreasToDesiredBounds(); } if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus) || (mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { // If frame is complete and has a next-in-flow, we need to delete // them now. Do not do this when a break-before is signaled because // the frame is going to get reflowed again (and may end up wanting // a next-in-flow where it ends up), unless it is an out of flow frame. if (NS_FRAME_IS_FULLY_COMPLETE(aFrameReflowStatus)) { nsIFrame* kidNextInFlow = mFrame->GetNextInFlow(); if (nullptr != kidNextInFlow) { // Remove all of the childs next-in-flows. Make sure that we ask // the right parent to do the removal (it's possible that the // parent is not this because we are executing pullup code). // Floats will eventually be removed via nsBlockFrame::RemoveFloat // which detaches the placeholder from the float. nsOverflowContinuationTracker::AutoFinish fini(aState.mOverflowTracker, mFrame); static_cast<nsContainerFrame*>(kidNextInFlow->GetParent()) ->DeleteNextInFlowChild(kidNextInFlow, true); } } } return rv; }
void nsVideoFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsVideoFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsVideoFrame::Reflow: availSize=%d,%d", aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); aStatus = NS_FRAME_COMPLETE; aMetrics.Width() = aReflowState.ComputedWidth(); aMetrics.Height() = aReflowState.ComputedHeight(); // stash this away so we can compute our inner area later mBorderPadding = aReflowState.ComputedPhysicalBorderPadding(); aMetrics.Width() += mBorderPadding.left + mBorderPadding.right; aMetrics.Height() += mBorderPadding.top + mBorderPadding.bottom; // Reflow the child frames. We may have up to two, an image frame // which is the poster, and a box frame, which is the video controls. for (nsIFrame* child : mFrames) { if (child->GetContent() == mPosterImage) { // Reflow the poster frame. nsImageFrame* imageFrame = static_cast<nsImageFrame*>(child); nsHTMLReflowMetrics kidDesiredSize(aReflowState); WritingMode wm = imageFrame->GetWritingMode(); LogicalSize availableSize = aReflowState.AvailableSize(wm); LogicalSize cbSize = aMetrics.Size(aMetrics.GetWritingMode()). ConvertTo(wm, aMetrics.GetWritingMode()); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, imageFrame, availableSize, &cbSize); nsRect posterRenderRect; if (ShouldDisplayPoster()) { posterRenderRect = nsRect(nsPoint(mBorderPadding.left, mBorderPadding.top), nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); } kidReflowState.SetComputedWidth(posterRenderRect.width); kidReflowState.SetComputedHeight(posterRenderRect.height); ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowState, posterRenderRect.x, posterRenderRect.y, 0, aStatus); FinishReflowChild(imageFrame, aPresContext, kidDesiredSize, &kidReflowState, posterRenderRect.x, posterRenderRect.y, 0); } else if (child->GetContent() == mVideoControls) { // Reflow the video controls frame. nsBoxLayoutState boxState(PresContext(), aReflowState.rendContext); nsSize size = child->GetSize(); nsBoxFrame::LayoutChildAt(boxState, child, nsRect(mBorderPadding.left, mBorderPadding.top, aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); if (child->GetSize() != size) { RefPtr<nsRunnable> event = new DispatchResizeToControls(child->GetContent()); nsContentUtils::AddScriptRunner(event); } } else if (child->GetContent() == mCaptionDiv) { // Reflow to caption div nsHTMLReflowMetrics kidDesiredSize(aReflowState); WritingMode wm = child->GetWritingMode(); LogicalSize availableSize = aReflowState.AvailableSize(wm); LogicalSize cbSize = aMetrics.Size(aMetrics.GetWritingMode()). ConvertTo(wm, aMetrics.GetWritingMode()); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, child, availableSize, &cbSize); nsSize size(aReflowState.ComputedWidth(), aReflowState.ComputedHeight()); size.width -= kidReflowState.ComputedPhysicalBorderPadding().LeftRight(); size.height -= kidReflowState.ComputedPhysicalBorderPadding().TopBottom(); kidReflowState.SetComputedWidth(std::max(size.width, 0)); kidReflowState.SetComputedHeight(std::max(size.height, 0)); ReflowChild(child, aPresContext, kidDesiredSize, kidReflowState, mBorderPadding.left, mBorderPadding.top, 0, aStatus); FinishReflowChild(child, aPresContext, kidDesiredSize, &kidReflowState, mBorderPadding.left, mBorderPadding.top, 0); } } 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, aReflowState, aMetrics); }
void nsFirstLetterFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aReflowStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsFirstLetterFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aReflowStatus); // Grab overflow list DrainOverflowFrames(aPresContext); nsIFrame* kid = mFrames.FirstChild(); // Setup reflow state for our child WritingMode wm = aReflowState.GetWritingMode(); LogicalSize availSize = aReflowState.AvailableSize(); const LogicalMargin& bp = aReflowState.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(); nsHTMLReflowMetrics kidMetrics(lineWM); // Reflow the child if (!aReflowState.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 = GetWritingMode(kid); LogicalSize kidAvailSize = availSize.ConvertTo(kidWritingMode, wm); nsHTMLReflowState rs(aPresContext, aReflowState, kid, kidAvailSize); nsLineLayout ll(aPresContext, nullptr, &aReflowState, nullptr, nullptr); ll.BeginLineReflow(bp.IStart(wm), bp.BStart(wm), availSize.ISize(wm), NS_UNCONSTRAINEDSIZE, false, true, kidWritingMode, nsSize(aReflowState.AvailableWidth(), aReflowState.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 = aReflowState.mLineLayout; bool pushedFrame; ll->SetInFirstLetter( mStyleContext->GetPseudo() == nsCSSPseudoElements::firstLetter); ll->BeginSpan(this, &aReflowState, 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); 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 (aReflowState.mLineLayout) { aReflowState.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, aReflowState, aMetrics); }
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, nsPresContext* aPresContext, nsBlockFrame* aFrame, bool aTopMarginRoot, bool aBottomMarginRoot, bool aBlockNeedsFloatManager, nscoord aConsumedHeight) : mBlock(aFrame), mPresContext(aPresContext), mReflowState(aReflowState), mPushedFloats(nullptr), mOverflowTracker(nullptr), mPrevBottomMargin(), mLineNumber(0), mFlags(0), mFloatBreakType(NS_STYLE_CLEAR_NONE), mConsumedHeight(aConsumedHeight) { SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nullptr); SetFlag(BRS_ISOVERFLOWCONTAINER, IS_TRUE_OVERFLOW_CONTAINER(aFrame)); const nsMargin& borderPadding = BorderPadding(); if (aTopMarginRoot || 0 != aReflowState.ComputedPhysicalBorderPadding().top) { SetFlag(BRS_ISTOPMARGINROOT, true); } if (aBottomMarginRoot || 0 != aReflowState.ComputedPhysicalBorderPadding().bottom) { SetFlag(BRS_ISBOTTOMMARGINROOT, true); } if (GetFlag(BRS_ISTOPMARGINROOT)) { SetFlag(BRS_APPLYTOPMARGIN, true); } if (aBlockNeedsFloatManager) { SetFlag(BRS_FLOAT_MGR, true); } mFloatManager = aReflowState.mFloatManager; NS_ASSERTION(mFloatManager, "FloatManager should be set in nsBlockReflowState" ); if (mFloatManager) { // Save the coordinate system origin for later. mFloatManager->GetTranslation(mFloatManagerX, mFloatManagerY); mFloatManager->PushState(&mFloatManagerStateBefore); // never popped } mReflowStatus = NS_FRAME_COMPLETE; mNextInFlow = static_cast<nsBlockFrame*>(mBlock->GetNextInFlow()); NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.ComputedWidth(), "have unconstrained width; this should only result from " "very large sizes, not attempts at intrinsic width " "calculation"); mContentArea.width = aReflowState.ComputedWidth(); // 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 != aReflowState.AvailableHeight()) { // 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. mBottomEdge = aReflowState.AvailableHeight() - borderPadding.bottom; mContentArea.height = std::max(0, mBottomEdge - borderPadding.top); } else { // When we are not in a paginated situation then we always use // an constrained height. SetFlag(BRS_UNCONSTRAINEDHEIGHT, true); mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE; } mContentArea.x = borderPadding.left; mY = mContentArea.y = borderPadding.top; mPrevChild = nullptr; mCurrentLine = aFrame->end_lines(); mMinLineHeight = aReflowState.CalcLineHeight(); }
nsresult nsVideoFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsVideoFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsVideoFrame::Reflow: availSize=%d,%d", aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); aStatus = NS_FRAME_COMPLETE; aMetrics.Width() = aReflowState.ComputedWidth(); aMetrics.Height() = aReflowState.ComputedHeight(); // stash this away so we can compute our inner area later mBorderPadding = aReflowState.ComputedPhysicalBorderPadding(); aMetrics.Width() += mBorderPadding.left + mBorderPadding.right; aMetrics.Height() += mBorderPadding.top + mBorderPadding.bottom; // Reflow the child frames. We may have up to two, an image frame // which is the poster, and a box frame, which is the video controls. for (nsIFrame *child = mFrames.FirstChild(); child; child = child->GetNextSibling()) { if (child->GetContent() == mPosterImage) { // Reflow the poster frame. nsImageFrame* imageFrame = static_cast<nsImageFrame*>(child); nsHTMLReflowMetrics kidDesiredSize(aReflowState.GetWritingMode()); nsSize availableSize = nsSize(aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, imageFrame, availableSize, aMetrics.Width(), aMetrics.Height()); uint32_t posterHeight, posterWidth; nsSize scaledPosterSize(0, 0); nsSize computedArea(aReflowState.ComputedWidth(), aReflowState.ComputedHeight()); nsPoint posterTopLeft(0, 0); nsCOMPtr<nsIDOMHTMLImageElement> posterImage = do_QueryInterface(mPosterImage); NS_ENSURE_TRUE(posterImage, NS_ERROR_FAILURE); posterImage->GetNaturalHeight(&posterHeight); posterImage->GetNaturalWidth(&posterWidth); if (ShouldDisplayPoster() && posterHeight && posterWidth) { gfxFloat scale = std::min(static_cast<float>(computedArea.width)/nsPresContext::CSSPixelsToAppUnits(static_cast<float>(posterWidth)), static_cast<float>(computedArea.height)/nsPresContext::CSSPixelsToAppUnits(static_cast<float>(posterHeight))); gfxSize scaledRatio = gfxSize(scale*posterWidth, scale*posterHeight); scaledPosterSize.width = nsPresContext::CSSPixelsToAppUnits(static_cast<float>(scaledRatio.width)); scaledPosterSize.height = nsPresContext::CSSPixelsToAppUnits(static_cast<int32_t>(scaledRatio.height)); } kidReflowState.SetComputedWidth(scaledPosterSize.width); kidReflowState.SetComputedHeight(scaledPosterSize.height); posterTopLeft.x = ((computedArea.width - scaledPosterSize.width) / 2) + mBorderPadding.left; posterTopLeft.y = ((computedArea.height - scaledPosterSize.height) / 2) + mBorderPadding.top; ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowState, posterTopLeft.x, posterTopLeft.y, 0, aStatus); FinishReflowChild(imageFrame, aPresContext, kidDesiredSize, &kidReflowState, posterTopLeft.x, posterTopLeft.y, 0); } else if (child->GetContent() == mVideoControls) { // Reflow the video controls frame. nsBoxLayoutState boxState(PresContext(), aReflowState.rendContext); nsSize size = child->GetSize(); nsBoxFrame::LayoutChildAt(boxState, child, nsRect(mBorderPadding.left, mBorderPadding.top, aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); if (child->GetSize() != size) { nsRefPtr<nsRunnable> event = new DispatchResizeToControls(child->GetContent()); nsContentUtils::AddScriptRunner(event); } } else if (child->GetContent() == mCaptionDiv) { // Reflow to caption div nsHTMLReflowMetrics kidDesiredSize(aReflowState.GetWritingMode()); nsSize availableSize = nsSize(aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, child, availableSize, aMetrics.Width(), aMetrics.Height()); nsSize size(aReflowState.ComputedWidth(), aReflowState.ComputedHeight()); size.width -= kidReflowState.ComputedPhysicalBorderPadding().LeftRight(); size.height -= kidReflowState.ComputedPhysicalBorderPadding().TopBottom(); kidReflowState.SetComputedWidth(std::max(size.width, 0)); kidReflowState.SetComputedHeight(std::max(size.height, 0)); ReflowChild(child, aPresContext, kidDesiredSize, kidReflowState, mBorderPadding.left, mBorderPadding.top, 0, aStatus); FinishReflowChild(child, aPresContext, kidDesiredSize, &kidReflowState, mBorderPadding.left, mBorderPadding.top, 0); } } 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, aReflowState, aMetrics); return NS_OK; }
void nsColumnSetFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { // Don't support interruption in columns nsPresContext::InterruptPreventer noInterrupts(aPresContext); DO_GLOBAL_REFLOW_COUNT("nsColumnSetFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; // Our children depend on our height if we have a fixed height. if (aReflowState.ComputedHeight() != NS_AUTOHEIGHT) { NS_ASSERTION(aReflowState.ComputedHeight() != NS_INTRINSICSIZE, "Unexpected computed height"); AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT); } else { RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT); } #ifdef DEBUG nsFrameList::Enumerator oc(GetChildList(kOverflowContainersList)); for (; !oc.AtEnd(); oc.Next()) { MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(oc.get())); } nsFrameList::Enumerator eoc(GetChildList(kExcessOverflowContainersList)); for (; !eoc.AtEnd(); eoc.Next()) { MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(eoc.get())); } #endif nsOverflowAreas ocBounds; nsReflowStatus ocStatus = NS_FRAME_COMPLETE; if (GetPrevInFlow()) { ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0, ocStatus); } //------------ Handle Incremental Reflow ----------------- ReflowConfig config = ChooseColumnStrategy(aReflowState); // If balancing, then we allow the last column to grow to unbounded // height during the first reflow. This gives us a way to estimate // what the average column height should be, because we can measure // the heights of all the columns and sum them up. But don't do this // if we have a next in flow because we don't want to suck all its // content back here and then have to push it out again! nsIFrame* nextInFlow = GetNextInFlow(); bool unboundedLastColumn = config.mIsBalancing && !nextInFlow; nsCollapsingMargin carriedOutBottomMargin; ColumnBalanceData colData; colData.mHasExcessHeight = false; bool feasible = ReflowColumns(aDesiredSize, aReflowState, aStatus, config, unboundedLastColumn, &carriedOutBottomMargin, colData); // If we're not balancing, then we're already done, since we should have // reflown all of our children, and there is no need for a binary search to // determine proper column height. if (config.mIsBalancing && !aPresContext->HasPendingInterrupt()) { FindBestBalanceHeight(aReflowState, aPresContext, config, colData, aDesiredSize, carriedOutBottomMargin, unboundedLastColumn, feasible, aStatus); } if (aPresContext->HasPendingInterrupt() && aReflowState.AvailableHeight() == NS_UNCONSTRAINEDSIZE) { // In this situation, we might be lying about our reflow status, because // our last kid (the one that got interrupted) was incomplete. Fix that. aStatus = NS_FRAME_COMPLETE; } NS_ASSERTION(NS_FRAME_IS_FULLY_COMPLETE(aStatus) || aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE, "Column set should be complete if the available height is unconstrained"); // Merge overflow container bounds and status. aDesiredSize.mOverflowAreas.UnionWith(ocBounds); NS_MergeReflowStatusInto(&aStatus, ocStatus); FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus, false); aDesiredSize.mCarriedOutBEndMargin = carriedOutBottomMargin; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsLeafBoxFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { // This is mostly a copy of nsBoxFrame::Reflow(). // We aren't able to share an implementation because of the frame // class hierarchy. If you make changes here, please keep // nsBoxFrame::Reflow in sync. DO_GLOBAL_REFLOW_COUNT("nsLeafBoxFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_ASSERTION(aReflowState.ComputedWidth() >=0 && aReflowState.ComputedHeight() >= 0, "Computed Size < 0"); #ifdef DO_NOISY_REFLOW printf("\n-------------Starting LeafBoxFrame Reflow ----------------------------\n"); printf("%p ** nsLBF::Reflow %d R: ", this, myCounter++); switch (aReflowState.reason) { case eReflowReason_Initial: printf("Ini");break; case eReflowReason_Incremental: printf("Inc");break; case eReflowReason_Resize: printf("Rsz");break; case eReflowReason_StyleChange: printf("Sty");break; case eReflowReason_Dirty: printf("Drt "); break; default:printf("<unknown>%d", aReflowState.reason);break; } printSize("AW", aReflowState.AvailableWidth()); printSize("AH", aReflowState.AvailableHeight()); printSize("CW", aReflowState.ComputedWidth()); printSize("CH", aReflowState.ComputedHeight()); printf(" *\n"); #endif aStatus = NS_FRAME_COMPLETE; // create the layout state nsBoxLayoutState state(aPresContext, aReflowState.rendContext); nsSize computedSize(aReflowState.ComputedWidth(),aReflowState.ComputedHeight()); nsMargin m; m = aReflowState.ComputedPhysicalBorderPadding(); //GetBorderAndPadding(m); // this happens sometimes. So lets handle it gracefully. if (aReflowState.ComputedHeight() == 0) { nsSize minSize = GetMinSize(state); computedSize.height = minSize.height - m.top - m.bottom; } nsSize prefSize(0,0); // if we are told to layout intrinic then get our preferred size. if (computedSize.width == NS_INTRINSICSIZE || computedSize.height == NS_INTRINSICSIZE) { prefSize = GetPrefSize(state); nsSize minSize = GetMinSize(state); nsSize maxSize = GetMaxSize(state); prefSize = BoundsCheck(minSize, prefSize, maxSize); } // get our desiredSize if (aReflowState.ComputedWidth() == NS_INTRINSICSIZE) { computedSize.width = prefSize.width; } else { computedSize.width += m.left + m.right; } if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) { computedSize.height = prefSize.height; } else { computedSize.height += m.top + m.bottom; } // handle reflow state min and max sizes // XXXbz the width handling here seems to be wrong, since // mComputedMin/MaxWidth is a content-box size, whole // computedSize.width is a border-box size... if (computedSize.width > aReflowState.ComputedMaxWidth()) computedSize.width = aReflowState.ComputedMaxWidth(); if (computedSize.width < aReflowState.ComputedMinWidth()) computedSize.width = aReflowState.ComputedMinWidth(); // Now adjust computedSize.height for our min and max computed // height. The only problem is that those are content-box sizes, // while computedSize.height is a border-box size. So subtract off // m.TopBottom() before adjusting, then readd it. computedSize.height = std::max(0, computedSize.height - m.TopBottom()); computedSize.height = NS_CSS_MINMAX(computedSize.height, aReflowState.ComputedMinHeight(), aReflowState.ComputedMaxHeight()); computedSize.height += m.TopBottom(); nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height); SetBounds(state, r); // layout our children Layout(state); // ok our child could have gotten bigger. So lets get its bounds aDesiredSize.Width() = mRect.width; aDesiredSize.Height() = mRect.height; aDesiredSize.SetTopAscent(GetBoxAscent(state)); // the overflow rect is set in SetBounds() above aDesiredSize.mOverflowAreas = GetOverflowAreas(); #ifdef DO_NOISY_REFLOW { printf("%p ** nsLBF(done) W:%d H:%d ", this, aDesiredSize.Width(), aDesiredSize.Height()); if (maxElementWidth) { printf("MW:%d\n", *maxElementWidth); } else { printf("MW:?\n"); } } #endif }
nsresult nsTableCellFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); if (aReflowState.mFlags.mSpecialHeightReflow) { FirstInFlow()->AddStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW); } // see if a special height reflow needs to occur due to having a pct height nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); aStatus = NS_FRAME_COMPLETE; nsSize availSize(aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); nsMargin borderPadding = aReflowState.ComputedPhysicalPadding(); nsMargin border; GetBorderWidth(border); borderPadding += border; nscoord topInset = borderPadding.top; nscoord rightInset = borderPadding.right; nscoord bottomInset = borderPadding.bottom; nscoord leftInset = borderPadding.left; // reduce available space by insets, if we're in a constrained situation availSize.width -= leftInset + rightInset; if (NS_UNCONSTRAINEDSIZE != availSize.height) availSize.height -= topInset + bottomInset; // Try to reflow the child into the available space. It might not // fit or might need continuing. if (availSize.height < 0) availSize.height = 1; nsHTMLReflowMetrics kidSize(aReflowState.GetWritingMode(), aDesiredSize.mFlags); kidSize.Width() = kidSize.Height() = 0; SetPriorAvailWidth(aReflowState.AvailableWidth()); nsIFrame* firstKid = mFrames.FirstChild(); NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame"); nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); if (aReflowState.mFlags.mSpecialHeightReflow) { const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(mRect.height - topInset - bottomInset); DISPLAY_REFLOW_CHANGE(); } else if (aPresContext->IsPaginated()) { nscoord computedUnpaginatedHeight = CalcUnpaginagedHeight(aPresContext, (nsTableCellFrame&)*this, *tableFrame, topInset + bottomInset); if (computedUnpaginatedHeight > 0) { const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(computedUnpaginatedHeight); DISPLAY_REFLOW_CHANGE(); } } else { SetHasPctOverHeight(false); } nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid, availSize); // Don't be a percent height observer if we're in the middle of // special-height reflow, in case we get an accidental NotifyPercentHeight() // call (which we shouldn't honor during special-height reflow) if (!aReflowState.mFlags.mSpecialHeightReflow) { // mPercentHeightObserver is for children of cells in quirks mode, // but only those than are tables in standards mode. NeedsToObserve // will determine how far this is propagated to descendants. kidReflowState.mPercentHeightObserver = this; } // Don't propagate special height reflow state to our kids kidReflowState.mFlags.mSpecialHeightReflow = false; if (aReflowState.mFlags.mSpecialHeightReflow || (FirstInFlow()->GetStateBits() & NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) { // We need to force the kid to have mVResize 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 height reflow. kidReflowState.mFlags.mVResize = true; } nsPoint kidOrigin(leftInset, topInset); nsRect origRect = firstKid->GetRect(); nsRect origVisualOverflow = firstKid->GetVisualOverflowRect(); bool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; ReflowChild(firstKid, aPresContext, kidSize, kidReflowState, kidOrigin.x, kidOrigin.y, 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 (GetStateBits() & NS_FRAME_IS_DIRTY) { InvalidateFrameSubtree(); } #ifdef DEBUG DebugCheckChildSize(firstKid, kidSize, availSize); #endif // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode // see testcase "emptyCells.html" nsIFrame* prevInFlow = GetPrevInFlow(); bool isEmpty; if (prevInFlow) { isEmpty = static_cast<nsTableCellFrame*>(prevInFlow)->GetContentEmpty(); } else { isEmpty = !CellHasVisibleContent(kidSize.Height(), tableFrame, firstKid); } SetContentEmpty(isEmpty); // Place the child FinishReflowChild(firstKid, aPresContext, kidSize, &kidReflowState, kidOrigin.x, kidOrigin.y, 0); nsTableFrame::InvalidateTableFrame(firstKid, origRect, origVisualOverflow, firstReflow); // first, compute the height which can be set w/o being restricted by aMaxSize.height nscoord cellHeight = kidSize.Height(); if (NS_UNCONSTRAINEDSIZE != cellHeight) { cellHeight += topInset + bottomInset; } // next determine the cell's width nscoord cellWidth = kidSize.Width(); // at this point, we've factored in the cell's style attributes // factor in border and padding if (NS_UNCONSTRAINEDSIZE != cellWidth) { cellWidth += leftInset + rightInset; } // set the cell's desired size and max element size aDesiredSize.Width() = cellWidth; aDesiredSize.Height() = cellHeight; // the overflow area will be computed when the child will be vertically aligned if (aReflowState.mFlags.mSpecialHeightReflow) { if (aDesiredSize.Height() > mRect.height) { // set a bit indicating that the pct height contents exceeded // the height that they could honor in the pass 2 reflow SetHasPctOverHeight(true); } if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) { aDesiredSize.Height() = mRect.height; } } // If our parent is in initial reflow, it'll handle invalidating our // entire overflow rect. if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) && nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) { InvalidateFrame(); } // remember the desired size for this reflow SetDesiredSize(aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
/* virtual */ void nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsRubyBaseContainerFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); if (!aReflowState.mLineLayout) { NS_ASSERTION( aReflowState.mLineLayout, "No line layout provided to RubyBaseContainerFrame reflow method."); aStatus = NS_FRAME_COMPLETE; return; } aStatus = NS_FRAME_COMPLETE; nscoord isize = 0; int baseNum = 0; nscoord leftoverSpace = 0; nscoord spaceApart = 0; WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode(); WritingMode frameWM = aReflowState.GetWritingMode(); LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding(); nscoord baseStart = 0; LogicalSize availSize(lineWM, aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); // Begin the line layout for each ruby text container in advance. for (uint32_t i = 0; i < mTextContainers.Length(); i++) { nsRubyTextContainerFrame* rtcFrame = mTextContainers.ElementAt(i); nsHTMLReflowState rtcReflowState(aPresContext, *aReflowState.parentReflowState, rtcFrame, availSize); rtcReflowState.mLineLayout = aReflowState.mLineLayout; // FIXME: Avoid using/needing the rtcReflowState argument rtcFrame->BeginRTCLineLayout(aPresContext, rtcReflowState); } for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) { nsIFrame* rbFrame = e.get(); if (rbFrame->GetType() != nsGkAtoms::rubyBaseFrame) { NS_ASSERTION(false, "Unrecognized child type for ruby base container"); continue; } nsReflowStatus frameReflowStatus; nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags); // Determine if we need more spacing between bases in the inline direction // depending on the inline size of the corresponding annotations // FIXME: The use of GetPrefISize here and below is easier but not ideal. It // would be better to use metrics from reflow. nscoord prefWidth = rbFrame->GetPrefISize(aReflowState.rendContext); nscoord textWidth = 0; for (uint32_t i = 0; i < mTextContainers.Length(); i++) { nsRubyTextFrame* rtFrame = do_QueryFrame(mTextContainers.ElementAt(i)-> PrincipalChildList().FrameAt(baseNum)); if (rtFrame) { int newWidth = rtFrame->GetPrefISize(aReflowState.rendContext); if (newWidth > textWidth) { textWidth = newWidth; } } } if (textWidth > prefWidth) { spaceApart = std::max((textWidth - prefWidth) / 2, spaceApart); leftoverSpace = spaceApart; } else { spaceApart = leftoverSpace; leftoverSpace = 0; } if (spaceApart > 0) { aReflowState.mLineLayout->AdvanceICoord(spaceApart); } baseStart = aReflowState.mLineLayout->GetCurrentICoord(); bool pushedFrame; aReflowState.mLineLayout->ReflowFrame(rbFrame, frameReflowStatus, &metrics, pushedFrame); NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented"); isize += metrics.ISize(lineWM); rbFrame->SetSize(LogicalSize(lineWM, metrics.ISize(lineWM), metrics.BSize(lineWM))); FinishReflowChild(rbFrame, aPresContext, metrics, &aReflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW); // Now reflow the ruby text boxes that correspond to this ruby base box. for (uint32_t i = 0; i < mTextContainers.Length(); i++) { nsRubyTextFrame* rtFrame = do_QueryFrame(mTextContainers.ElementAt(i)-> PrincipalChildList().FrameAt(baseNum)); nsRubyTextContainerFrame* rtcFrame = mTextContainers.ElementAt(i); if (rtFrame) { nsHTMLReflowMetrics rtcMetrics(*aReflowState.parentReflowState, aDesiredSize.mFlags); nsHTMLReflowState rtcReflowState(aPresContext, *aReflowState.parentReflowState, rtcFrame, availSize); rtcReflowState.mLineLayout = rtcFrame->GetLineLayout(); rtcFrame->ReflowRubyTextFrame(rtFrame, rbFrame, baseStart, aPresContext, rtcMetrics, rtcReflowState); } } baseNum++; } // Reflow ruby annotations which do not have a corresponding ruby base box due // to a ruby base shortage. According to the spec, an empty ruby base is // assumed to exist for each of these annotations. bool continueReflow = true; while (continueReflow) { continueReflow = false; for (uint32_t i = 0; i < mTextContainers.Length(); i++) { nsRubyTextFrame* rtFrame = do_QueryFrame(mTextContainers.ElementAt(i)-> PrincipalChildList().FrameAt(baseNum)); nsRubyTextContainerFrame* rtcFrame = mTextContainers.ElementAt(i); if (rtFrame) { continueReflow = true; nsHTMLReflowMetrics rtcMetrics(*aReflowState.parentReflowState, aDesiredSize.mFlags); nsHTMLReflowState rtcReflowState(aPresContext, *aReflowState.parentReflowState, rtcFrame, availSize); rtcReflowState.mLineLayout = rtcFrame->GetLineLayout(); rtcFrame->ReflowRubyTextFrame(rtFrame, nullptr, baseStart, aPresContext, rtcMetrics, rtcReflowState); // Update the inline coord to make space for subsequent ruby annotations // (since there is no corresponding base inline size to use). baseStart += rtcMetrics.ISize(lineWM); } } baseNum++; } aDesiredSize.ISize(lineWM) = isize; nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState, borderPadding, lineWM, frameWM); }
void nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame, nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, const nsRect& aContainingBlock, AbsPosReflowFlags aFlags, nsIFrame* aKidFrame, nsReflowStatus& aStatus, nsOverflowAreas* aOverflowAreas) { #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent); printf("abs pos "); if (aKidFrame) { nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); } char width[16]; char height[16]; PrettyUC(aReflowState.AvailableWidth(), width, 16); PrettyUC(aReflowState.AvailableHeight(), height, 16); printf(" a=%s,%s ", width, height); PrettyUC(aReflowState.ComputedWidth(), width, 16); PrettyUC(aReflowState.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(aReflowState.ComputedSize(wm).ISize(wm) != NS_UNCONSTRAINEDSIZE, "Must have a useful inline-size _somewhere_"); availISize = aReflowState.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 |= nsHTMLReflowState::STATIC_POS_IS_CB_ORIGIN; } } nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame, LogicalSize(wm, availISize, NS_UNCONSTRAINEDSIZE), &logicalCBSize, rsFlags); // Get the border values WritingMode outerWM = aReflowState.GetWritingMode(); const LogicalMargin border(outerWM, aReflowState.mStyleBorder->GetComputedBorder()); const LogicalMargin margin = kidReflowState.ComputedLogicalMargin().ConvertTo(outerWM, wm); bool constrainBSize = (aReflowState.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) <= aReflowState.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) { kidReflowState.AvailableBSize() = aReflowState.AvailableBSize() - border.ConvertTo(wm, outerWM).BStart(wm) - kidReflowState.ComputedLogicalMargin().BStart(wm); if (NS_AUTOOFFSET != kidReflowState.ComputedLogicalOffsets().BStart(wm)) { kidReflowState.AvailableBSize() -= kidReflowState.ComputedLogicalOffsets().BStart(wm); } } // Do the reflow nsHTMLReflowMetrics kidDesiredSize(kidReflowState); aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); const LogicalSize kidSize = kidDesiredSize.Size(wm).ConvertTo(outerWM, wm); LogicalMargin offsets = kidReflowState.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. if ((NS_AUTOOFFSET == offsets.IStart(outerWM)) || (NS_AUTOOFFSET == offsets.BStart(outerWM))) { if (-1 == logicalCBSize.ISize(wm)) { // Get the containing block width/height logicalCBSize = kidReflowState.ComputeContainingBlockRectangle(aPresContext, &aReflowState); } if (NS_AUTOOFFSET == offsets.IStart(outerWM)) { NS_ASSERTION(NS_AUTOOFFSET != offsets.IEnd(outerWM), "Can't solve for both start and end"); offsets.IStart(outerWM) = logicalCBSize.ConvertTo(outerWM, wm).ISize(outerWM) - offsets.IEnd(outerWM) - margin.IStartEnd(outerWM) - kidSize.ISize(outerWM); } if (NS_AUTOOFFSET == offsets.BStart(outerWM)) { offsets.BStart(outerWM) = logicalCBSize.ConvertTo(outerWM, wm).BSize(outerWM) - offsets.BEnd(outerWM) - margin.BStartEnd(outerWM) - kidSize.BSize(outerWM); } kidReflowState.SetComputedLogicalOffsets(offsets.ConvertTo(wm, outerWM)); } // 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 = kidReflowState.mStylePosition->mOffset; if (!(offsets.GetLeftUnit() == eStyleUnit_Auto && offsets.GetRightUnit() == eStyleUnit_Auto) || (rsFlags & nsHTMLReflowState::STATIC_POS_IS_CB_ORIGIN)) { r.x += aContainingBlock.x; } if (!(offsets.GetTopUnit() == eStyleUnit_Auto && offsets.GetBottomUnit() == eStyleUnit_Auto) || (rsFlags & nsHTMLReflowState::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, &kidReflowState, nsDidReflowStatus::FINISHED); #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1); printf("abs pos "); if (aKidFrame) { 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()); } }
nsresult ViewportFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("ViewportFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow"); // Initialize OUT parameters aStatus = NS_FRAME_COMPLETE; // Because |Reflow| sets mComputedHeight on the child to // availableHeight. AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT); // 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(aReflowState.ComputedWidth(), aReflowState.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 kidHeight = 0; nsresult rv = NS_OK; if (mFrames.NotEmpty()) { // Deal with a non-incremental reflow or an incremental reflow // targeted at our one-and-only principal child frame. if (aReflowState.ShouldReflowAllKids() || aReflowState.mFlags.mVResize || NS_SUBTREE_DIRTY(mFrames.FirstChild())) { // Reflow our one-and-only principal child frame nsIFrame* kidFrame = mFrames.FirstChild(); nsHTMLReflowMetrics kidDesiredSize(aReflowState); nsSize availableSpace(aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, availableSpace); // Reflow the frame kidReflowState.SetComputedHeight(aReflowState.ComputedHeight()); rv = ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, 0, 0, 0, aStatus); kidHeight = kidDesiredSize.Height(); FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, nullptr, 0, 0, 0); } else { kidHeight = mFrames.FirstChild()->GetSize().height; } } NS_ASSERTION(aReflowState.AvailableWidth() != NS_UNCONSTRAINEDSIZE, "shouldn't happen anymore"); // Return the max size as our desired size aDesiredSize.Width() = aReflowState.AvailableWidth(); // Being flowed initially at an unconstrained height means we should // return our child's intrinsic size. aDesiredSize.Height() = aReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE ? aReflowState.ComputedHeight() : kidHeight; aDesiredSize.SetOverflowAreasToDesiredBounds(); if (mFrames.NotEmpty()) { ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mFrames.FirstChild()); } if (IsAbsoluteContainer()) { // Make a copy of the reflow state and change the computed width and height // to reflect the available space for the fixed items nsHTMLReflowState reflowState(aReflowState); if (reflowState.AvailableHeight() == NS_UNCONSTRAINEDSIZE) { // We have an intrinsic-height document with abs-pos/fixed-pos children. // Set the available height and mComputedHeight to our chosen height. reflowState.AvailableHeight() = aDesiredSize.Height(); // Not having border/padding simplifies things NS_ASSERTION(reflowState.ComputedPhysicalBorderPadding() == nsMargin(0,0,0,0), "Viewports can't have border/padding"); reflowState.SetComputedHeight(aDesiredSize.Height()); } nsRect rect = AdjustReflowStateAsContainingBlock(&reflowState); // Just reflow all the fixed-pos frames. rv = GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus, rect, false, true, true, // XXX could be optimized &aDesiredSize.mOverflowAreas); } // 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, aReflowState, aDesiredSize); return rv; }