/* virtual */ LogicalSize nsMathMLSelectedFrame::ComputeSize(nsRenderingContext *aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize, nscoord aAvailableISize, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, ComputeSizeFlags aFlags) { nsIFrame* childFrame = GetSelectedFrame(); if (childFrame) { // Delegate size computation to the child frame. // Try to account for border/padding/margin on this frame and the child, // though we don't really support them during reflow anyway... nscoord availableISize = aAvailableISize - aBorder.ISize(aWM) - aPadding.ISize(aWM) - aMargin.ISize(aWM); LogicalSize cbSize = aCBSize - aBorder - aPadding - aMargin; SizeComputationInput offsetState(childFrame, aRenderingContext, aWM, availableISize); LogicalSize size = childFrame->ComputeSize(aRenderingContext, aWM, cbSize, availableISize, offsetState.ComputedLogicalMargin().Size(aWM), offsetState.ComputedLogicalBorderPadding().Size(aWM) - offsetState.ComputedLogicalPadding().Size(aWM), offsetState.ComputedLogicalPadding().Size(aWM), aFlags); return size + offsetState.ComputedLogicalBorderPadding().Size(aWM); } return LogicalSize(aWM); }
// Return the inline-size that the float (including margins) will take up // in the writing mode of the containing block. If this returns // NS_UNCONSTRAINEDSIZE, we're dealing with an orthogonal block that // has block-size:auto, and we'll need to actually reflow it to find out // how much inline-size it will occupy in the containing block's mode. static nscoord FloatMarginISize(const nsHTMLReflowState& aCBReflowState, nscoord aFloatAvailableISize, nsIFrame *aFloat, const nsCSSOffsetState& aFloatOffsetState) { AutoMaybeDisableFontInflation an(aFloat); WritingMode wm = aFloatOffsetState.GetWritingMode(); LogicalSize floatSize = aFloat->ComputeSize( aCBReflowState.rendContext, wm, aCBReflowState.ComputedSize(wm), aFloatAvailableISize, aFloatOffsetState.ComputedLogicalMargin().Size(wm), aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm) - aFloatOffsetState.ComputedLogicalPadding().Size(wm), aFloatOffsetState.ComputedLogicalPadding().Size(wm), nsIFrame::ComputeSizeFlags::eShrinkWrap); WritingMode cbwm = aCBReflowState.GetWritingMode(); nscoord floatISize = floatSize.ConvertTo(cbwm, wm).ISize(cbwm); if (floatISize == NS_UNCONSTRAINEDSIZE) { return NS_UNCONSTRAINEDSIZE; // reflow is needed to get the true size } return floatISize + aFloatOffsetState.ComputedLogicalMargin().Size(wm). ConvertTo(cbwm, wm).ISize(cbwm) + aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm). ConvertTo(cbwm, wm).ISize(cbwm); }
/* virtual */ LogicalSize nsFieldSetFrame::ComputeSize(nsRenderingContext *aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize, nscoord aAvailableISize, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, ComputeSizeFlags aFlags) { LogicalSize result = nsContainerFrame::ComputeSize(aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin, aBorder, aPadding, aFlags); // XXX The code below doesn't make sense if the caller's writing mode // is orthogonal to this frame's. Not sure yet what should happen then; // for now, just bail out. if (aWM.IsVertical() != GetWritingMode().IsVertical()) { return result; } // Fieldsets never shrink below their min width. // If we're a container for font size inflation, then shrink // wrapping inside of us should not apply font size inflation. AutoMaybeDisableFontInflation an(this); nscoord minISize = GetMinISize(aRenderingContext); if (minISize > result.ISize(aWM)) { result.ISize(aWM) = minISize; } return result; }
// Only reflow the selected child ... void nsMathMLSelectedFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { aStatus = NS_FRAME_COMPLETE; aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); mBoundingMetrics = nsBoundingMetrics(); nsIFrame* childFrame = GetSelectedFrame(); if (childFrame) { WritingMode wm = childFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); ReflowChild(childFrame, aPresContext, aDesiredSize, childReflowState, aStatus); SaveReflowAndBoundingMetricsFor(childFrame, aDesiredSize, aDesiredSize.mBoundingMetrics); mBoundingMetrics = aDesiredSize.mBoundingMetrics; } FinalizeReflow(*aReflowState.rendContext, aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
LogicalSize nsTextControlFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize, nscoord aAvailableISize, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, bool aShrinkWrap) { float inflation = nsLayoutUtils::FontSizeInflationFor(this); // XXX CalcIntrinsicSize needs to be updated to use a LogicalSize nsSize autoSize; nsresult rv = CalcIntrinsicSize(aRenderingContext, autoSize, inflation); if (NS_FAILED(rv)) { // What now? autoSize.SizeTo(0, 0); } #ifdef DEBUG // Note: Ancestor ComputeAutoSize only computes a width if we're auto-width else if (StylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) { LogicalSize ancestorAutoSize = nsContainerFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin, aBorder, aPadding, aShrinkWrap); // Disabled when there's inflation; see comment in GetPrefSize. NS_ASSERTION(inflation != 1.0f || ancestorAutoSize.Width(aWM) == autoSize.width, "Incorrect size computed by ComputeAutoSize?"); } #endif return LogicalSize(aWM, autoSize); }
// Only reflow the selected child ... void nsMathMLSelectedFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); mPresentationData.flags &= ~NS_MATHML_ERROR; aStatus.Reset(); aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); mBoundingMetrics = nsBoundingMetrics(); nsIFrame* childFrame = GetSelectedFrame(); if (childFrame) { WritingMode wm = childFrame->GetWritingMode(); LogicalSize availSize = aReflowInput.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; ReflowInput childReflowInput(aPresContext, aReflowInput, childFrame, availSize); ReflowChild(childFrame, aPresContext, aDesiredSize, childReflowInput, aStatus); SaveReflowAndBoundingMetricsFor(childFrame, aDesiredSize, aDesiredSize.mBoundingMetrics); mBoundingMetrics = aDesiredSize.mBoundingMetrics; } FinalizeReflow(aReflowInput.mRenderingContext->GetDrawTarget(), aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); }
void nsMeterFrame::ReflowBarFrame(nsIFrame* aBarFrame, nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { bool vertical = ResolvedOrientationIsVertical(); WritingMode wm = aBarFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState reflowState(aPresContext, aReflowState, aBarFrame, availSize); nscoord size = vertical ? aReflowState.ComputedHeight() : aReflowState.ComputedWidth(); nscoord xoffset = aReflowState.ComputedPhysicalBorderPadding().left; nscoord yoffset = aReflowState.ComputedPhysicalBorderPadding().top; // NOTE: Introduce a new function getPosition in the content part ? HTMLMeterElement* meterElement = static_cast<HTMLMeterElement*>(mContent); double max = meterElement->Max(); double min = meterElement->Min(); double value = meterElement->Value(); double position = max - min; position = position != 0 ? (value - min) / position : 1; size = NSToCoordRound(size * position); if (!vertical && (wm.IsVertical() ? wm.IsVerticalRL() : !wm.IsBidiLTR())) { xoffset += aReflowState.ComputedWidth() - size; } // The bar position is *always* constrained. if (vertical) { // We want the bar to begin at the bottom. yoffset += aReflowState.ComputedHeight() - size; size -= reflowState.ComputedPhysicalMargin().TopBottom() + reflowState.ComputedPhysicalBorderPadding().TopBottom(); size = std::max(size, 0); reflowState.SetComputedHeight(size); } else { size -= reflowState.ComputedPhysicalMargin().LeftRight() + reflowState.ComputedPhysicalBorderPadding().LeftRight(); size = std::max(size, 0); reflowState.SetComputedWidth(size); } xoffset += reflowState.ComputedPhysicalMargin().left; yoffset += reflowState.ComputedPhysicalMargin().top; nsHTMLReflowMetrics barDesiredSize(reflowState); ReflowChild(aBarFrame, aPresContext, barDesiredSize, reflowState, xoffset, yoffset, 0, aStatus); FinishReflowChild(aBarFrame, aPresContext, barDesiredSize, &reflowState, xoffset, yoffset, 0); }
static nscoord ComputeDescendantISize(const ReflowInput& aAncestorReflowInput, nsIFrame *aDescendantFrame) { nsIFrame *ancestorFrame = aAncestorReflowInput.mFrame->FirstInFlow(); if (aDescendantFrame == ancestorFrame) { return aAncestorReflowInput.ComputedISize(); } AutoTArray<nsIFrame*, 16> frames; for (nsIFrame *f = aDescendantFrame; f != ancestorFrame; f = f->GetParent()->FirstInFlow()) { frames.AppendElement(f); } // This ignores the inline-size contributions made by scrollbars, though in // reality we don't have any scrollbars on the sorts of devices on // which we use font inflation, so it's not a problem. But it may // occasionally cause problems when writing tests on desktop. uint32_t len = frames.Length(); ReflowInput *reflowInputs = static_cast<ReflowInput*> (moz_xmalloc(sizeof(ReflowInput) * len)); nsPresContext *presContext = aDescendantFrame->PresContext(); for (uint32_t i = 0; i < len; ++i) { const ReflowInput &parentReflowInput = (i == 0) ? aAncestorReflowInput : reflowInputs[i - 1]; nsIFrame *frame = frames[len - i - 1]; WritingMode wm = frame->GetWritingMode(); LogicalSize availSize = parentReflowInput.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; MOZ_ASSERT(frame->GetParent()->FirstInFlow() == parentReflowInput.mFrame->FirstInFlow(), "bad logic in this function"); new (reflowInputs + i) ReflowInput(presContext, parentReflowInput, frame, availSize); } MOZ_ASSERT(reflowInputs[len - 1].mFrame == aDescendantFrame, "bad logic in this function"); nscoord result = reflowInputs[len - 1].ComputedISize(); for (uint32_t i = len; i-- != 0; ) { reflowInputs[i].~ReflowInput(); } free(reflowInputs); return result; }
void nsTableOuterFrame::OuterBeginReflowChild(nsPresContext* aPresContext, nsIFrame* aChildFrame, const nsHTMLReflowState& aOuterRS, void* aChildRSSpace, nscoord aAvailISize) { // work around pixel rounding errors, round down to ensure we don't exceed the avail height in WritingMode wm = aChildFrame->GetWritingMode(); LogicalSize outerSize = aOuterRS.AvailableSize(wm); nscoord availBSize = outerSize.BSize(wm); if (NS_UNCONSTRAINEDSIZE != availBSize) { if (mCaptionFrames.FirstChild() == aChildFrame) { availBSize = NS_UNCONSTRAINEDSIZE; } else { LogicalMargin margin(wm); GetChildMargin(aPresContext, aOuterRS, aChildFrame, outerSize.ISize(wm), margin); NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.BStart(wm), "No unconstrainedsize arithmetic, please"); availBSize -= margin.BStart(wm); NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.BEnd(wm), "No unconstrainedsize arithmetic, please"); availBSize -= margin.BEnd(wm); } } LogicalSize availSize(wm, aAvailISize, availBSize); // 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; } } }
void nsTableWrapperFrame::OuterBeginReflowChild(nsPresContext* aPresContext, nsIFrame* aChildFrame, const ReflowInput& aOuterRI, Maybe<ReflowInput>& aChildRI, nscoord aAvailISize) { // work around pixel rounding errors, round down to ensure we don't exceed the avail height in WritingMode wm = aChildFrame->GetWritingMode(); LogicalSize outerSize = aOuterRI.AvailableSize(wm); nscoord availBSize = outerSize.BSize(wm); if (NS_UNCONSTRAINEDSIZE != availBSize) { if (mCaptionFrames.FirstChild() == aChildFrame) { availBSize = NS_UNCONSTRAINEDSIZE; } else { LogicalMargin margin(wm); GetChildMargin(aPresContext, aOuterRI, aChildFrame, outerSize.ISize(wm), margin); NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.BStart(wm), "No unconstrainedsize arithmetic, please"); availBSize -= margin.BStart(wm); NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.BEnd(wm), "No unconstrainedsize arithmetic, please"); availBSize -= margin.BEnd(wm); } } LogicalSize availSize(wm, aAvailISize, availBSize); // create and init the child reflow state, using passed-in Maybe<>, // so that caller can use it after we return. aChildRI.emplace(aPresContext, aOuterRI, aChildFrame, availSize, nullptr, ReflowInput::CALLER_WILL_INIT); InitChildReflowInput(*aPresContext, *aChildRI); // see if we need to reset top-of-page due to a caption if (aChildRI->mFlags.mIsTopOfPage && mCaptionFrames.FirstChild() == aChildFrame) { uint8_t captionSide = GetCaptionSide(); if (captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM || captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE) { aChildRI->mFlags.mIsTopOfPage = false; } } }
// Compute the margin-box inline size of aChildFrame given the inputs. // If aMarginResult is non-null, fill it with the part of the // margin-isize that was contributed by the margin. static nscoord ChildShrinkWrapISize(nsRenderingContext *aRenderingContext, nsIFrame *aChildFrame, WritingMode aWM, LogicalSize aCBSize, nscoord aAvailableISize, nscoord *aMarginResult = nullptr) { AutoMaybeDisableFontInflation an(aChildFrame); // For the caption frame, child's WM may differ from the table's main WM. WritingMode childWM = aChildFrame->GetWritingMode(); SizeComputationInput offsets(aChildFrame, aRenderingContext, aWM, aCBSize.ISize(aWM)); LogicalSize marginSize = offsets.ComputedLogicalMargin().Size(childWM).ConvertTo(aWM, childWM); LogicalSize paddingSize = offsets.ComputedLogicalPadding().Size(childWM).ConvertTo(aWM, childWM); LogicalSize bpSize = offsets.ComputedLogicalBorderPadding().Size(childWM).ConvertTo(aWM, childWM); LogicalSize size = aChildFrame->ComputeSize(aRenderingContext, aWM, aCBSize, aAvailableISize, marginSize, bpSize - paddingSize, paddingSize, nsIFrame::ComputeSizeFlags::eShrinkWrap); if (aMarginResult) { *aMarginResult = offsets.ComputedLogicalMargin().IStartEnd(aWM); } return size.ISize(aWM) + marginSize.ISize(aWM) + bpSize.ISize(aWM); }
LogicalSize nsTextControlFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize, nscoord aAvailableISize, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, ComputeSizeFlags aFlags) { float inflation = nsLayoutUtils::FontSizeInflationFor(this); LogicalSize autoSize = CalcIntrinsicSize(aRenderingContext, aWM, inflation); // Note: nsContainerFrame::ComputeAutoSize only computes the inline-size (and // only for 'auto'), the block-size it returns is always NS_UNCONSTRAINEDSIZE. const nsStyleCoord& iSizeCoord = StylePosition()->ISize(aWM); if (iSizeCoord.GetUnit() == eStyleUnit_Auto) { if (aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) { // CalcIntrinsicSize isn't aware of grid-item margin-box clamping, so we // fall back to nsContainerFrame's ComputeAutoSize to handle that. // XXX maybe a font-inflation issue here? (per the assertion below). autoSize.ISize(aWM) = nsContainerFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin, aBorder, aPadding, aFlags).ISize(aWM); } #ifdef DEBUG else { LogicalSize ancestorAutoSize = nsContainerFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin, aBorder, aPadding, aFlags); // Disabled when there's inflation; see comment in GetXULPrefSize. MOZ_ASSERT(inflation != 1.0f || ancestorAutoSize.ISize(aWM) == autoSize.ISize(aWM), "Incorrect size computed by ComputeAutoSize?"); } #endif } return autoSize; }
/* virtual */ LogicalSize nsBackdropFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize, nscoord aAvailableISize, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, bool aShrinkWrap) { // Note that this frame is a child of the viewport frame. LogicalSize result(aWM, 0xdeadbeef, NS_UNCONSTRAINEDSIZE); if (aShrinkWrap) { result.ISize(aWM) = 0; } else { result.ISize(aWM) = aAvailableISize - aMargin.ISize(aWM) - aBorder.ISize(aWM) - aPadding.ISize(aWM); } return result; }
void nsTextControlFrame::ReflowTextControlChild(nsIFrame* aKid, nsPresContext* aPresContext, const ReflowInput& aReflowInput, nsReflowStatus& aStatus, ReflowOutput& aParentDesiredSize) { // compute available size and frame offsets for child WritingMode wm = aKid->GetWritingMode(); LogicalSize availSize = aReflowInput.ComputedSizeWithPadding(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; ReflowInput kidReflowInput(aPresContext, aReflowInput, aKid, availSize, nullptr, ReflowInput::CALLER_WILL_INIT); // Override padding with our computed padding in case we got it from theming or percentage kidReflowInput.Init(aPresContext, nullptr, nullptr, &aReflowInput.ComputedPhysicalPadding()); // Set computed width and computed height for the child kidReflowInput.SetComputedWidth(aReflowInput.ComputedWidth()); kidReflowInput.SetComputedHeight(aReflowInput.ComputedHeight()); // Offset the frame by the size of the parent's border nscoord xOffset = aReflowInput.ComputedPhysicalBorderPadding().left - aReflowInput.ComputedPhysicalPadding().left; nscoord yOffset = aReflowInput.ComputedPhysicalBorderPadding().top - aReflowInput.ComputedPhysicalPadding().top; // reflow the child ReflowOutput desiredSize(aReflowInput); ReflowChild(aKid, aPresContext, desiredSize, kidReflowInput, xOffset, yOffset, 0, aStatus); // place the child FinishReflowChild(aKid, aPresContext, desiredSize, &kidReflowInput, xOffset, yOffset, 0); // consider the overflow aParentDesiredSize.mOverflowAreas.UnionWith(desiredSize.mOverflowAreas); }
void nsMathMLTokenFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); mPresentationData.flags &= ~NS_MATHML_ERROR; // initializations needed for empty markup like <mtag></mtag> aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); nsIFrame* childFrame = GetFirstPrincipalChild(); while (childFrame) { // ask our children to compute their bounding metrics nsHTMLReflowMetrics childDesiredSize(aReflowState.GetWritingMode(), aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); WritingMode wm = childFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, aStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); childFrame = childFrame->GetNextSibling(); } // place and size children FinalizeReflow(aReflowState.rendContext->GetDrawTarget(), aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsGridContainerFrame::CalculateTrackSizes(const LogicalSize& aPercentageBasis, const nsStylePosition* aStyle, nsTArray<TrackSize>& aColSizes, nsTArray<TrackSize>& aRowSizes) { aColSizes.SetLength(mGridColEnd - 1); aRowSizes.SetLength(mGridRowEnd - 1); WritingMode wm = GetWritingMode(); InitializeTrackSizes(aPercentageBasis.ISize(wm), aStyle->mGridTemplateColumns.mMinTrackSizingFunctions, aStyle->mGridTemplateColumns.mMaxTrackSizingFunctions, aStyle->mGridAutoColumnsMin, aStyle->mGridAutoColumnsMax, aColSizes); InitializeTrackSizes(aPercentageBasis.BSize(wm), aStyle->mGridTemplateRows.mMinTrackSizingFunctions, aStyle->mGridTemplateRows.mMaxTrackSizingFunctions, aStyle->mGridAutoRowsMin, aStyle->mGridAutoRowsMax, aRowSizes); }
LogicalSize nsTextControlFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize, nscoord aAvailableISize, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, bool aShrinkWrap) { float inflation = nsLayoutUtils::FontSizeInflationFor(this); LogicalSize autoSize(aWM); nsresult rv = CalcIntrinsicSize(aRenderingContext, aWM, autoSize, inflation); if (NS_FAILED(rv)) { // What now? autoSize.SizeTo(aWM, 0, 0); } #ifdef DEBUG // Note: Ancestor ComputeAutoSize only computes a width if we're auto-width else { const nsStyleCoord& inlineStyleCoord = aWM.IsVertical() ? StylePosition()->mHeight : StylePosition()->mWidth; if (inlineStyleCoord.GetUnit() == eStyleUnit_Auto) { LogicalSize ancestorAutoSize = nsContainerFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin, aBorder, aPadding, aShrinkWrap); // Disabled when there's inflation; see comment in GetPrefSize. MOZ_ASSERT(inflation != 1.0f || ancestorAutoSize.ISize(aWM) == autoSize.ISize(aWM), "Incorrect size computed by ComputeAutoSize?"); } } #endif return autoSize; }
// Compute the margin-box width of aChildFrame given the inputs. If // aMarginResult is non-null, fill it with the part of the margin-width // that was contributed by the margin. static nscoord ChildShrinkWrapWidth(nsRenderingContext *aRenderingContext, nsIFrame *aChildFrame, nsSize aCBSize, nscoord aAvailableWidth, nscoord *aMarginResult = nullptr) { AutoMaybeDisableFontInflation an(aChildFrame); nsCSSOffsetState offsets(aChildFrame, aRenderingContext, aCBSize.width); WritingMode wm = offsets.GetWritingMode(); LogicalSize size = aChildFrame->ComputeSize(aRenderingContext, wm, LogicalSize(wm, aCBSize), aAvailableWidth, offsets.ComputedLogicalMargin().Size(wm), offsets.ComputedLogicalBorderPadding().Size(wm) - offsets.ComputedLogicalPadding().Size(wm), offsets.ComputedLogicalPadding().Size(wm), nsIFrame::ComputeSizeFlags::eShrinkWrap); if (aMarginResult) *aMarginResult = offsets.ComputedLogicalMargin().IStartEnd(wm); return size.ISize(wm) + offsets.ComputedLogicalMargin().IStartEnd(wm) + offsets.ComputedLogicalBorderPadding().IStartEnd(wm); }
nscoord nsTableWrapperFrame::ChildShrinkWrapISize(nsRenderingContext* aRenderingContext, nsIFrame* aChildFrame, WritingMode aWM, LogicalSize aCBSize, nscoord aAvailableISize, nscoord* aMarginResult) const { AutoMaybeDisableFontInflation an(aChildFrame); // For the caption frame, child's WM may differ from the table's main WM. WritingMode childWM = aChildFrame->GetWritingMode(); SizeComputationInput offsets(aChildFrame, aRenderingContext, aWM, aCBSize.ISize(aWM)); LogicalSize marginSize = offsets.ComputedLogicalMargin().Size(childWM).ConvertTo(aWM, childWM); LogicalSize paddingSize = offsets.ComputedLogicalPadding().Size(childWM).ConvertTo(aWM, childWM); LogicalSize bpSize = offsets.ComputedLogicalBorderPadding().Size(childWM).ConvertTo(aWM, childWM); // Shrink-wrap aChildFrame by default, except if we're a stretched grid item. auto flags = ComputeSizeFlags::eShrinkWrap; auto parent = GetParent(); nsIAtom* parentFrameType = parent ? parent->GetType() : nullptr; bool isGridItem = (parentFrameType == nsGkAtoms::gridContainerFrame && !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)); if (MOZ_UNLIKELY(isGridItem) && !StyleMargin()->HasInlineAxisAuto(aWM)) { auto inlineAxisAlignment = aWM.IsOrthogonalTo(parent->GetWritingMode()) ? StylePosition()->UsedAlignSelf(parent->StyleContext()) : StylePosition()->UsedJustifySelf(parent->StyleContext()); if (inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL || inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH) { flags = nsIFrame::ComputeSizeFlags::eDefault; } } LogicalSize size = aChildFrame->ComputeSize(aRenderingContext, aWM, aCBSize, aAvailableISize, marginSize, bpSize - paddingSize, paddingSize, flags); if (aMarginResult) { *aMarginResult = offsets.ComputedLogicalMargin().IStartEnd(aWM); } return size.ISize(aWM) + marginSize.ISize(aWM) + bpSize.ISize(aWM); }
/* virtual */ LogicalSize nsTableCaptionFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize, nscoord aAvailableISize, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, bool aShrinkWrap) { LogicalSize result = nsBlockFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin, aBorder, aPadding, aShrinkWrap); // If we're a container for font size inflation, then shrink // wrapping inside of us should not apply font size inflation. AutoMaybeDisableFontInflation an(this); // XXX todo: make this aware of vertical writing modes uint8_t captionSide = StyleTableBorder()->mCaptionSide; if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT || captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) { result.ISize(aWM) = GetMinISize(aRenderingContext); } else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP || captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) { // The outer frame constrains our available width to the width of // the table. Grow if our min-width is bigger than that, but not // larger than the containing block width. (It would really be nice // to transmit that information another way, so we could grow up to // the table's available width, but that's harder.) nscoord min = GetMinISize(aRenderingContext); if (min > aCBSize.ISize(aWM)) { min = aCBSize.ISize(aWM); } if (min > result.ISize(aWM)) { result.ISize(aWM) = min; } } return result; }
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); }
/* virtual */ LogicalSize nsSVGOuterSVGFrame::ComputeSize(nsRenderingContext *aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize, nscoord aAvailableISize, const LogicalSize& aMargin, const LogicalSize& aBorder, const LogicalSize& aPadding, uint32_t aFlags) { if (IsRootOfImage() || IsRootOfReplacedElementSubDoc()) { // The embedding element has sized itself using the CSS replaced element // sizing rules, using our intrinsic dimensions as necessary. The SVG spec // says that the width and height of embedded SVG is overridden by the // width and height of the embedding element, so we just need to size to // the viewport that the embedding element has established for us. return aCBSize; } LogicalSize cbSize = aCBSize; IntrinsicSize intrinsicSize = GetIntrinsicSize(); if (!mContent->GetParent()) { // We're the root of the outermost browsing context, so we need to scale // cbSize by the full-zoom so that SVGs with percentage width/height zoom: NS_ASSERTION(aCBSize.ISize(aWM) != NS_AUTOHEIGHT && aCBSize.BSize(aWM) != NS_AUTOHEIGHT, "root should not have auto-width/height containing block"); cbSize.ISize(aWM) *= PresContext()->GetFullZoom(); cbSize.BSize(aWM) *= PresContext()->GetFullZoom(); // We also need to honour the width and height attributes' default values // of 100% when we're the root of a browsing context. (GetIntrinsicSize() // doesn't report these since there's no such thing as a percentage // intrinsic size. Also note that explicit percentage values are mapped // into style, so the following isn't for them.) SVGSVGElement* content = static_cast<SVGSVGElement*>(mContent); nsSVGLength2 &width = content->mLengthAttributes[SVGSVGElement::ATTR_WIDTH]; if (width.IsPercentage()) { NS_ABORT_IF_FALSE(intrinsicSize.width.GetUnit() == eStyleUnit_None, "GetIntrinsicSize should have reported no " "intrinsic width"); float val = width.GetAnimValInSpecifiedUnits() / 100.0f; if (val < 0.0f) val = 0.0f; intrinsicSize.width.SetCoordValue(val * cbSize.Width(aWM)); } nsSVGLength2 &height = content->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT]; NS_ASSERTION(aCBSize.BSize(aWM) != NS_AUTOHEIGHT, "root should not have auto-height containing block"); if (height.IsPercentage()) { NS_ABORT_IF_FALSE(intrinsicSize.height.GetUnit() == eStyleUnit_None, "GetIntrinsicSize should have reported no " "intrinsic height"); float val = height.GetAnimValInSpecifiedUnits() / 100.0f; if (val < 0.0f) val = 0.0f; intrinsicSize.height.SetCoordValue(val * cbSize.Height(aWM)); } NS_ABORT_IF_FALSE(intrinsicSize.height.GetUnit() == eStyleUnit_Coord && intrinsicSize.width.GetUnit() == eStyleUnit_Coord, "We should have just handled the only situation where" "we lack an intrinsic height or width."); } return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(aWM, aRenderingContext, this, intrinsicSize, GetIntrinsicRatio(), cbSize, aMargin, aBorder, aPadding); }
void nsRubyFrame::ReflowSegment(nsPresContext* aPresContext, const ReflowInput& aReflowInput, nsRubyBaseContainerFrame* aBaseContainer, nsReflowStatus& aStatus) { WritingMode lineWM = aReflowInput.mLineLayout->GetWritingMode(); LogicalSize availSize(lineWM, aReflowInput.AvailableISize(), aReflowInput.AvailableBSize()); WritingMode rubyWM = GetWritingMode(); NS_ASSERTION(!rubyWM.IsOrthogonalTo(lineWM), "Ruby frame writing-mode shouldn't be orthogonal to its line"); AutoRubyTextContainerArray textContainers(aBaseContainer); const uint32_t rtcCount = textContainers.Length(); ReflowOutput baseMetrics(aReflowInput); bool pushedFrame; aReflowInput.mLineLayout->ReflowFrame(aBaseContainer, aStatus, &baseMetrics, pushedFrame); if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) { if (aBaseContainer != mFrames.FirstChild()) { // Some segments may have been reflowed before, hence it is not // a break-before for the ruby container. aStatus = NS_INLINE_LINE_BREAK_AFTER(NS_FRAME_NOT_COMPLETE); PushChildren(aBaseContainer, aBaseContainer->GetPrevSibling()); aReflowInput.mLineLayout->SetDirtyNextLine(); } // This base container is not placed at all, we can skip all // text containers paired with it. return; } if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // It always promise that if the status is incomplete, there is a // break occurs. Break before has been processed above. However, // it is possible that break after happens with the frame reflow // completed. It happens if there is a force break at the end. MOZ_ASSERT(NS_INLINE_IS_BREAK_AFTER(aStatus)); // Find the previous sibling which we will // insert new continuations after. nsIFrame* lastChild; if (rtcCount > 0) { lastChild = textContainers.LastElement(); } else { lastChild = aBaseContainer; } // Create continuations for the base container nsIFrame* newBaseContainer = CreateNextInFlow(aBaseContainer); // newBaseContainer is null if there are existing next-in-flows. // We only need to move and push if there were not. if (newBaseContainer) { // Move the new frame after all the text containers mFrames.RemoveFrame(newBaseContainer); mFrames.InsertFrame(nullptr, lastChild, newBaseContainer); // Create continuations for text containers nsIFrame* newLastChild = newBaseContainer; for (uint32_t i = 0; i < rtcCount; i++) { nsIFrame* newTextContainer = CreateNextInFlow(textContainers[i]); MOZ_ASSERT(newTextContainer, "Next-in-flow of rtc should not exist " "if the corresponding rbc does not"); mFrames.RemoveFrame(newTextContainer); mFrames.InsertFrame(nullptr, newLastChild, newTextContainer); newLastChild = newTextContainer; } } if (lastChild != mFrames.LastChild()) { // Always push the next frame after the last child in this segment. // It is possible that we pulled it back before our next-in-flow // drain our overflow. PushChildren(lastChild->GetNextSibling(), lastChild); aReflowInput.mLineLayout->SetDirtyNextLine(); } } else { // If the ruby base container is reflowed completely, the line // layout will remove the next-in-flows of that frame. But the // line layout is not aware of the ruby text containers, hence // it is necessary to remove them here. for (uint32_t i = 0; i < rtcCount; i++) { nsIFrame* nextRTC = textContainers[i]->GetNextInFlow(); if (nextRTC) { nextRTC->GetParent()->DeleteNextInFlowChild(nextRTC, true); } } } nscoord segmentISize = baseMetrics.ISize(lineWM); const nsSize dummyContainerSize; LogicalRect baseRect = aBaseContainer->GetLogicalRect(lineWM, dummyContainerSize); // We need to position our rtc frames on one side or the other of the // base container's rect, using a coordinate space that's relative to // the ruby frame. Right now, the base container's rect's block-axis // position is relative to the block container frame containing the // lines, so we use 0 instead. (i.e. we assume that the base container // is adjacent to the ruby frame's block-start edge.) // XXX We may need to add border/padding here. See bug 1055667. baseRect.BStart(lineWM) = 0; // The rect for offsets of text containers. LogicalRect offsetRect = baseRect; for (uint32_t i = 0; i < rtcCount; i++) { nsRubyTextContainerFrame* textContainer = textContainers[i]; WritingMode rtcWM = textContainer->GetWritingMode(); nsReflowStatus textReflowStatus; ReflowOutput textMetrics(aReflowInput); ReflowInput textReflowInput(aPresContext, aReflowInput, textContainer, availSize.ConvertTo(rtcWM, lineWM)); // FIXME We probably shouldn't be using the same nsLineLayout for // the text containers. But it should be fine now as we are // not actually using this line layout to reflow something, // but just read the writing mode from it. textReflowInput.mLineLayout = aReflowInput.mLineLayout; textContainer->Reflow(aPresContext, textMetrics, textReflowInput, textReflowStatus); // Ruby text containers always return NS_FRAME_COMPLETE even when // they have continuations, because the breaking has already been // handled when reflowing the base containers. NS_ASSERTION(textReflowStatus == NS_FRAME_COMPLETE, "Ruby text container must not break itself inside"); // The metrics is initialized with reflow state of this ruby frame, // hence the writing-mode is tied to rubyWM instead of rtcWM. LogicalSize size = textMetrics.Size(rubyWM).ConvertTo(lineWM, rubyWM); textContainer->SetSize(lineWM, size); nscoord reservedISize = RubyUtils::GetReservedISize(textContainer); segmentISize = std::max(segmentISize, size.ISize(lineWM) + reservedISize); uint8_t rubyPosition = textContainer->StyleText()->mRubyPosition; MOZ_ASSERT(rubyPosition == NS_STYLE_RUBY_POSITION_OVER || rubyPosition == NS_STYLE_RUBY_POSITION_UNDER); Maybe<LogicalSide> side; if (rubyPosition == NS_STYLE_RUBY_POSITION_OVER) { side.emplace(lineWM.LogicalSideForLineRelativeDir(eLineRelativeDirOver)); } else if (rubyPosition == NS_STYLE_RUBY_POSITION_UNDER) { side.emplace(lineWM.LogicalSideForLineRelativeDir(eLineRelativeDirUnder)); } else { // XXX inter-character support in bug 1055672 MOZ_ASSERT_UNREACHABLE("Unsupported ruby-position"); } LogicalPoint position(lineWM); if (side.isSome()) { if (side.value() == eLogicalSideBStart) { offsetRect.BStart(lineWM) -= size.BSize(lineWM); offsetRect.BSize(lineWM) += size.BSize(lineWM); position = offsetRect.Origin(lineWM); } else if (side.value() == eLogicalSideBEnd) { position = offsetRect.Origin(lineWM) + LogicalPoint(lineWM, 0, offsetRect.BSize(lineWM)); offsetRect.BSize(lineWM) += size.BSize(lineWM); } else { MOZ_ASSERT_UNREACHABLE("???"); } } // Using a dummy container-size here, so child positioning may not be // correct. We will fix it in nsLineLayout after the whole line is // reflowed. FinishReflowChild(textContainer, aPresContext, textMetrics, &textReflowInput, lineWM, position, dummyContainerSize, 0); } MOZ_ASSERT(baseRect.ISize(lineWM) == offsetRect.ISize(lineWM), "Annotations should only be placed on the block directions"); nscoord deltaISize = segmentISize - baseMetrics.ISize(lineWM); if (deltaISize <= 0) { RubyUtils::ClearReservedISize(aBaseContainer); } else { RubyUtils::SetReservedISize(aBaseContainer, deltaISize); aReflowInput.mLineLayout->AdvanceICoord(deltaISize); } // Set block leadings of the base container nscoord startLeading = baseRect.BStart(lineWM) - offsetRect.BStart(lineWM); nscoord endLeading = offsetRect.BEnd(lineWM) - baseRect.BEnd(lineWM); // XXX When bug 765861 gets fixed, this warning should be upgraded. NS_WARNING_ASSERTION(startLeading >= 0 && endLeading >= 0, "Leadings should be non-negative (because adding " "ruby annotation can only increase the size)"); mBStartLeading = std::max(mBStartLeading, startLeading); mBEndLeading = std::max(mBEndLeading, endLeading); }
void nsProgressFrame::ReflowBarFrame(nsIFrame* aBarFrame, nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { bool vertical = ResolvedOrientationIsVertical(); WritingMode wm = aBarFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState reflowState(aPresContext, aReflowState, aBarFrame, availSize); nscoord size = vertical ? aReflowState.ComputedHeight() : aReflowState.ComputedWidth(); nscoord xoffset = aReflowState.ComputedPhysicalBorderPadding().left; nscoord yoffset = aReflowState.ComputedPhysicalBorderPadding().top; double position = static_cast<HTMLProgressElement*>(mContent)->Position(); // Force the bar's size to match the current progress. // When indeterminate, the progress' size will be 100%. if (position >= 0.0) { size *= position; } if (!vertical && (wm.IsVertical() ? wm.IsVerticalRL() : !wm.IsBidiLTR())) { xoffset += aReflowState.ComputedWidth() - size; } // The bar size is fixed in these cases: // - the progress position is determined: the bar size is fixed according // to it's value. // - the progress position is indeterminate and the bar appearance should be // shown as native: the bar size is forced to 100%. // Otherwise (when the progress is indeterminate and the bar appearance isn't // native), the bar size isn't fixed and can be set by the author. if (position != -1 || ShouldUseNativeStyle()) { if (vertical) { // We want the bar to begin at the bottom. yoffset += aReflowState.ComputedHeight() - size; size -= reflowState.ComputedPhysicalMargin().TopBottom() + reflowState.ComputedPhysicalBorderPadding().TopBottom(); size = std::max(size, 0); reflowState.SetComputedHeight(size); } else { size -= reflowState.ComputedPhysicalMargin().LeftRight() + reflowState.ComputedPhysicalBorderPadding().LeftRight(); size = std::max(size, 0); reflowState.SetComputedWidth(size); } } else if (vertical) { // For vertical progress bars, we need to position the bar specificly when // the width isn't constrained (position == -1 and !ShouldUseNativeStyle()) // because aReflowState.ComputedHeight() - size == 0. yoffset += aReflowState.ComputedHeight() - reflowState.ComputedHeight(); } xoffset += reflowState.ComputedPhysicalMargin().left; yoffset += reflowState.ComputedPhysicalMargin().top; nsHTMLReflowMetrics barDesiredSize(aReflowState); ReflowChild(aBarFrame, aPresContext, barDesiredSize, reflowState, xoffset, yoffset, 0, aStatus); FinishReflowChild(aBarFrame, aPresContext, barDesiredSize, &reflowState, xoffset, yoffset, 0); }
void nsFieldSetFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_PRECONDITION(aReflowState.ComputedISize() != NS_INTRINSICSIZE, "Should have a precomputed inline-size!"); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; nsOverflowAreas ocBounds; nsReflowStatus ocStatus = NS_FRAME_COMPLETE; if (GetPrevInFlow()) { ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0, ocStatus); } //------------ Handle Incremental Reflow ----------------- bool reflowInner; bool reflowLegend; nsIFrame* legend = GetLegend(); nsIFrame* inner = GetInner(); if (aReflowState.ShouldReflowAllKids()) { reflowInner = inner != nullptr; reflowLegend = legend != nullptr; } else { reflowInner = inner && NS_SUBTREE_DIRTY(inner); reflowLegend = legend && NS_SUBTREE_DIRTY(legend); } // We don't allow fieldsets to break vertically. If we did, we'd // need logic here to push and pull overflow frames. // Since we're not applying our padding in this frame, we need to add it here // to compute the available width for our children. WritingMode wm = GetWritingMode(); WritingMode innerWM = inner ? inner->GetWritingMode() : wm; WritingMode legendWM = legend ? legend->GetWritingMode() : wm; LogicalSize innerAvailSize = aReflowState.ComputedSizeWithPadding(innerWM); LogicalSize legendAvailSize = aReflowState.ComputedSizeWithPadding(legendWM); innerAvailSize.BSize(innerWM) = legendAvailSize.BSize(legendWM) = NS_UNCONSTRAINEDSIZE; NS_ASSERTION(!inner || nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext, inner, nsLayoutUtils::MIN_ISIZE) <= innerAvailSize.ISize(innerWM), "Bogus availSize.ISize; should be bigger"); NS_ASSERTION(!legend || nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext, legend, nsLayoutUtils::MIN_ISIZE) <= legendAvailSize.ISize(legendWM), "Bogus availSize.ISize; should be bigger"); // get our border and padding LogicalMargin border = aReflowState.ComputedLogicalBorderPadding() - aReflowState.ComputedLogicalPadding(); // Figure out how big the legend is if there is one. // get the legend's margin LogicalMargin legendMargin(wm); // reflow the legend only if needed Maybe<nsHTMLReflowState> legendReflowState; if (legend) { legendReflowState.emplace(aPresContext, aReflowState, legend, legendAvailSize); } if (reflowLegend) { nsHTMLReflowMetrics legendDesiredSize(aReflowState); // We'll move the legend to its proper place later, so the position // and containerSize passed here are unimportant. const nsSize dummyContainerSize; ReflowChild(legend, aPresContext, legendDesiredSize, *legendReflowState, wm, LogicalPoint(wm), dummyContainerSize, NS_FRAME_NO_MOVE_FRAME, aStatus); #ifdef NOISY_REFLOW printf(" returned (%d, %d)\n", legendDesiredSize.Width(), legendDesiredSize.Height()); #endif // figure out the legend's rectangle legendMargin = legend->GetLogicalUsedMargin(wm); mLegendRect = LogicalRect(wm, 0, 0, legendDesiredSize.ISize(wm) + legendMargin.IStartEnd(wm), legendDesiredSize.BSize(wm) + legendMargin.BStartEnd(wm)); nscoord oldSpace = mLegendSpace; mLegendSpace = 0; if (mLegendRect.BSize(wm) > border.BStart(wm)) { // center the border on the legend mLegendSpace = mLegendRect.BSize(wm) - border.BStart(wm); } else { mLegendRect.BStart(wm) = (border.BStart(wm) - mLegendRect.BSize(wm)) / 2; } // if the legend space changes then we need to reflow the // content area as well. if (mLegendSpace != oldSpace && inner) { reflowInner = true; } FinishReflowChild(legend, aPresContext, legendDesiredSize, legendReflowState.ptr(), wm, LogicalPoint(wm), dummyContainerSize, NS_FRAME_NO_MOVE_FRAME); } else if (!legend) { mLegendRect.SetEmpty(); mLegendSpace = 0; } else { // mLegendSpace and mLegendRect haven't changed, but we need // the used margin when placing the legend. legendMargin = legend->GetLogicalUsedMargin(wm); } // This containerSize is incomplete as yet: it does not include the size // of the |inner| frame itself. nsSize containerSize = (LogicalSize(wm, 0, mLegendSpace) + border.Size(wm)).GetPhysicalSize(wm); // reflow the content frame only if needed if (reflowInner) { nsHTMLReflowState kidReflowState(aPresContext, aReflowState, inner, innerAvailSize, nullptr, nsHTMLReflowState::CALLER_WILL_INIT); // Override computed padding, in case it's percentage padding kidReflowState.Init(aPresContext, nullptr, nullptr, &aReflowState.ComputedPhysicalPadding()); // Our child is "height:100%" but we actually want its height to be reduced // by the amount of content-height the legend is eating up, unless our // height is unconstrained (in which case the child's will be too). if (aReflowState.ComputedBSize() != NS_UNCONSTRAINEDSIZE) { kidReflowState.SetComputedBSize( std::max(0, aReflowState.ComputedBSize() - mLegendSpace)); } if (aReflowState.ComputedMinBSize() > 0) { kidReflowState.ComputedMinBSize() = std::max(0, aReflowState.ComputedMinBSize() - mLegendSpace); } if (aReflowState.ComputedMaxBSize() != NS_UNCONSTRAINEDSIZE) { kidReflowState.ComputedMaxBSize() = std::max(0, aReflowState.ComputedMaxBSize() - mLegendSpace); } nsHTMLReflowMetrics kidDesiredSize(kidReflowState, aDesiredSize.mFlags); // Reflow the frame NS_ASSERTION(kidReflowState.ComputedPhysicalMargin() == nsMargin(0,0,0,0), "Margins on anonymous fieldset child not supported!"); LogicalPoint pt(wm, border.IStart(wm), border.BStart(wm) + mLegendSpace); // We don't know the correct containerSize until we have reflowed |inner|, // so we use a dummy value for now; FinishReflowChild will fix the position // if necessary. const nsSize dummyContainerSize; ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState, wm, pt, dummyContainerSize, 0, aStatus); // Update containerSize to account for size of the inner frame, so that // FinishReflowChild can position it correctly. containerSize += kidDesiredSize.PhysicalSize(); FinishReflowChild(inner, aPresContext, kidDesiredSize, &kidReflowState, wm, pt, containerSize, 0); NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus); } else if (inner) { // |inner| didn't need to be reflowed but we do need to include its size // in containerSize. containerSize += inner->GetSize(); } LogicalRect contentRect(wm); if (inner) { // We don't support margins on inner, so our content rect is just the // inner's border-box. (We don't really care about container size at this // point, as we'll figure out the actual positioning later.) contentRect = inner->GetLogicalRect(wm, containerSize); } // Our content rect must fill up the available width LogicalSize availSize = aReflowState.ComputedSizeWithPadding(wm); if (availSize.ISize(wm) > contentRect.ISize(wm)) { contentRect.ISize(wm) = innerAvailSize.ISize(wm); } if (legend) { // The legend is positioned inline-wards within the inner's content rect // (so that padding on the fieldset affects the legend position). LogicalRect innerContentRect = contentRect; innerContentRect.Deflate(wm, aReflowState.ComputedLogicalPadding()); // If the inner content rect is larger than the legend, we can align the // legend. if (innerContentRect.ISize(wm) > mLegendRect.ISize(wm)) { int32_t align = static_cast<nsLegendFrame*> (legend->GetContentInsertionFrame())->GetAlign(); if (!wm.IsBidiLTR()) { if (align == NS_STYLE_TEXT_ALIGN_LEFT || align == NS_STYLE_TEXT_ALIGN_MOZ_LEFT) { align = NS_STYLE_TEXT_ALIGN_END; } else if (align == NS_STYLE_TEXT_ALIGN_RIGHT || align == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT) { align = NS_STYLE_TEXT_ALIGN_DEFAULT; } } switch (align) { case NS_STYLE_TEXT_ALIGN_END: mLegendRect.IStart(wm) = innerContentRect.IEnd(wm) - mLegendRect.ISize(wm); break; case NS_STYLE_TEXT_ALIGN_CENTER: case NS_STYLE_TEXT_ALIGN_MOZ_CENTER: // Note: rounding removed; there doesn't seem to be any need mLegendRect.IStart(wm) = innerContentRect.IStart(wm) + (innerContentRect.ISize(wm) - mLegendRect.ISize(wm)) / 2; break; default: mLegendRect.IStart(wm) = innerContentRect.IStart(wm); break; } } else { // otherwise make place for the legend mLegendRect.IStart(wm) = innerContentRect.IStart(wm); innerContentRect.ISize(wm) = mLegendRect.ISize(wm); contentRect.ISize(wm) = mLegendRect.ISize(wm) + aReflowState.ComputedLogicalPadding().IStartEnd(wm); } // place the legend LogicalRect actualLegendRect = mLegendRect; actualLegendRect.Deflate(wm, legendMargin); LogicalPoint actualLegendPos(actualLegendRect.Origin(wm)); // Note that legend's writing mode may be different from the fieldset's, // so we need to convert offsets before applying them to it (bug 1134534). LogicalMargin offsets = legendReflowState->ComputedLogicalOffsets(). ConvertTo(wm, legendReflowState->GetWritingMode()); nsHTMLReflowState::ApplyRelativePositioning(legend, wm, offsets, &actualLegendPos, containerSize); legend->SetPosition(wm, actualLegendPos, containerSize); nsContainerFrame::PositionFrameView(legend); nsContainerFrame::PositionChildViews(legend); } // Return our size and our result. LogicalSize finalSize(wm, contentRect.ISize(wm) + border.IStartEnd(wm), mLegendSpace + border.BStartEnd(wm) + (inner ? inner->BSize(wm) : 0)); aDesiredSize.SetSize(wm, finalSize); aDesiredSize.SetOverflowAreasToDesiredBounds(); if (legend) { ConsiderChildOverflow(aDesiredSize.mOverflowAreas, legend); } if (inner) { ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inner); } // Merge overflow container bounds and status. aDesiredSize.mOverflowAreas.UnionWith(ocBounds); NS_MergeReflowStatusInto(&aStatus, ocStatus); FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); InvalidateFrame(); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext, nsHTMLReflowMetrics& aButtonDesiredSize, const nsHTMLReflowState& aButtonReflowState, nsIFrame* aFirstKid) { // Buttons have some bonus renderer-determined border/padding, // which occupies part of the button's content-box area: const nsMargin focusPadding = mRenderer.GetAddedButtonBorderAndPadding(); WritingMode wm = aFirstKid->GetWritingMode(); LogicalSize availSize = aButtonReflowState.ComputedSize(GetWritingMode()); availSize.BSize(wm) = NS_INTRINSICSIZE; // Indent the child inside us by the focus border. We must do this separate // from the regular border. availSize.ISize(wm) -= LogicalMargin(wm, focusPadding).IStartEnd(wm); // See whether out availSize's width is big enough. If it's smaller than our // intrinsic min width, that means that the kid wouldn't really fit; for a // better look in such cases we adjust the available width and our left // offset to allow the kid to spill left into our padding. nscoord xoffset = focusPadding.left + aButtonReflowState.ComputedPhysicalBorderPadding().left; nscoord extrawidth = GetMinISize(aButtonReflowState.rendContext) - aButtonReflowState.ComputedWidth(); if (extrawidth > 0) { nscoord extraleft = extrawidth / 2; nscoord extraright = extrawidth - extraleft; NS_ASSERTION(extraright >=0, "How'd that happen?"); // Do not allow the extras to be bigger than the relevant padding extraleft = std::min(extraleft, aButtonReflowState.ComputedPhysicalPadding().left); extraright = std::min(extraright, aButtonReflowState.ComputedPhysicalPadding().right); xoffset -= extraleft; availSize.Width(wm) = availSize.Width(wm) + extraleft + extraright; } availSize.Width(wm) = std::max(availSize.Width(wm), 0); // Give child a clone of the button's reflow state, with height/width reduced // by focusPadding, so that descendants with height:100% don't protrude. nsHTMLReflowState adjustedButtonReflowState = CloneReflowStateWithReducedContentBox(aButtonReflowState, focusPadding); nsHTMLReflowState contentsReflowState(aPresContext, adjustedButtonReflowState, aFirstKid, availSize); nsReflowStatus contentsReflowStatus; nsHTMLReflowMetrics contentsDesiredSize(aButtonReflowState); ReflowChild(aFirstKid, aPresContext, contentsDesiredSize, contentsReflowState, xoffset, focusPadding.top + aButtonReflowState.ComputedPhysicalBorderPadding().top, 0, contentsReflowStatus); MOZ_ASSERT(NS_FRAME_IS_COMPLETE(contentsReflowStatus), "We gave button-contents frame unconstrained available height, " "so it should be complete"); // Compute the button's content-box height: nscoord buttonContentBoxHeight = 0; if (aButtonReflowState.ComputedHeight() != NS_INTRINSICSIZE) { // Button has a fixed height -- that's its content-box height. buttonContentBoxHeight = aButtonReflowState.ComputedHeight(); } else { // Button is intrinsically sized -- it should shrinkwrap the // button-contents' height, plus any focus-padding space: buttonContentBoxHeight = contentsDesiredSize.Height() + focusPadding.TopBottom(); // Make sure we obey min/max-height in the case when we're doing intrinsic // sizing (we get it for free when we have a non-intrinsic // aButtonReflowState.ComputedHeight()). Note that we do this before // adjusting for borderpadding, since mComputedMaxHeight and // mComputedMinHeight are content heights. buttonContentBoxHeight = NS_CSS_MINMAX(buttonContentBoxHeight, aButtonReflowState.ComputedMinHeight(), aButtonReflowState.ComputedMaxHeight()); } // Center child vertically in the button // (technically, inside of the button's focus-padding area) nscoord extraSpace = buttonContentBoxHeight - focusPadding.TopBottom() - contentsDesiredSize.Height(); nscoord yoffset = std::max(0, extraSpace / 2); // Adjust yoffset to be in terms of the button's frame-rect, instead of // its focus-padding rect: yoffset += focusPadding.top + aButtonReflowState.ComputedPhysicalBorderPadding().top; // Place the child FinishReflowChild(aFirstKid, aPresContext, contentsDesiredSize, &contentsReflowState, xoffset, yoffset, 0); // Make sure we have a useful 'ascent' value for the child if (contentsDesiredSize.BlockStartAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) { WritingMode wm = aButtonReflowState.GetWritingMode(); contentsDesiredSize.SetBlockStartAscent(aFirstKid->GetLogicalBaseline(wm)); } // OK, we're done with the child frame. // Use what we learned to populate the button frame's reflow metrics. // * Button's height & width are content-box size + border-box contribution: aButtonDesiredSize.Width() = aButtonReflowState.ComputedWidth() + aButtonReflowState.ComputedPhysicalBorderPadding().LeftRight(); aButtonDesiredSize.Height() = buttonContentBoxHeight + aButtonReflowState.ComputedPhysicalBorderPadding().TopBottom(); // * Button's ascent is its child's ascent, plus the child's y-offset // within our frame: aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.BlockStartAscent() + yoffset); aButtonDesiredSize.SetOverflowAreasToDesiredBounds(); }
// Returns true if this function managed to successfully move a frame, and // false if it could not process the position change, and a reflow should // be performed instead. bool RecomputePosition(nsIFrame* aFrame) { // Don't process position changes on table frames, since we already handle // the dynamic position change on the table wrapper frame, and the // reflow-based fallback code path also ignores positions on inner table // frames. if (aFrame->GetType() == nsGkAtoms::tableFrame) { return true; } const nsStyleDisplay* display = aFrame->StyleDisplay(); // Changes to the offsets of a non-positioned element can safely be ignored. if (display->mPosition == NS_STYLE_POSITION_STATIC) { return true; } // Don't process position changes on frames which have views or the ones which // have a view somewhere in their descendants, because the corresponding view // needs to be repositioned properly as well. if (aFrame->HasView() || (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) { StyleChangeReflow(aFrame, nsChangeHint_NeedReflow); return false; } aFrame->SchedulePaint(); // For relative positioning, we can simply update the frame rect if (display->IsRelativelyPositionedStyle()) { // Move the frame if (display->mPosition == NS_STYLE_POSITION_STICKY) { if (display->IsInnerTableStyle()) { // We don't currently support sticky positioning of inner table // elements (bug 975644). Bail. // // When this is fixed, remove the null-check for the computed // offsets in nsTableRowFrame::ReflowChildren. return true; } // Update sticky positioning for an entire element at once, starting with // the first continuation or ib-split sibling. // It's rare that the frame we already have isn't already the first // continuation or ib-split sibling, but it can happen when styles differ // across continuations such as ::first-line or ::first-letter, and in // those cases we will generally (but maybe not always) do the work twice. nsIFrame* firstContinuation = nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame); StickyScrollContainer::ComputeStickyOffsets(firstContinuation); StickyScrollContainer* ssc = StickyScrollContainer::GetStickyScrollContainerForFrame( firstContinuation); if (ssc) { ssc->PositionContinuations(firstContinuation); } } else { MOZ_ASSERT(NS_STYLE_POSITION_RELATIVE == display->mPosition, "Unexpected type of positioning"); for (nsIFrame* cont = aFrame; cont; cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) { nsIFrame* cb = cont->GetContainingBlock(); nsMargin newOffsets; WritingMode wm = cb->GetWritingMode(); const LogicalSize size(wm, cb->GetContentRectRelativeToSelf().Size()); ReflowInput::ComputeRelativeOffsets(wm, cont, size, newOffsets); NS_ASSERTION(newOffsets.left == -newOffsets.right && newOffsets.top == -newOffsets.bottom, "ComputeRelativeOffsets should return valid results"); // ReflowInput::ApplyRelativePositioning would work here, but // since we've already checked mPosition and aren't changing the frame's // normal position, go ahead and add the offsets directly. cont->SetPosition(cont->GetNormalPosition() + nsPoint(newOffsets.left, newOffsets.top)); } } return true; } // For the absolute positioning case, set up a fake HTML reflow state for // the frame, and then get the offsets and size from it. If the frame's size // doesn't need to change, we can simply update the frame position. Otherwise // we fall back to a reflow. nsRenderingContext rc( aFrame->PresContext()->PresShell()->CreateReferenceRenderingContext()); // Construct a bogus parent reflow state so that there's a usable // containing block reflow state. nsIFrame* parentFrame = aFrame->GetParent(); WritingMode parentWM = parentFrame->GetWritingMode(); WritingMode frameWM = aFrame->GetWritingMode(); LogicalSize parentSize = parentFrame->GetLogicalSize(); nsFrameState savedState = parentFrame->GetStateBits(); ReflowInput parentReflowInput(aFrame->PresContext(), parentFrame, &rc, parentSize); parentFrame->RemoveStateBits(~nsFrameState(0)); parentFrame->AddStateBits(savedState); // The bogus parent state here was created with no parent state of its own, // and therefore it won't have an mCBReflowInput set up. // But we may need one (for InitCBReflowInput in a child state), so let's // try to create one here for the cases where it will be needed. Maybe<ReflowInput> cbReflowInput; nsIFrame* cbFrame = parentFrame->GetContainingBlock(); if (cbFrame && (aFrame->GetContainingBlock() != parentFrame || parentFrame->GetType() == nsGkAtoms::tableFrame)) { LogicalSize cbSize = cbFrame->GetLogicalSize(); cbReflowInput.emplace(cbFrame->PresContext(), cbFrame, &rc, cbSize); cbReflowInput->ComputedPhysicalMargin() = cbFrame->GetUsedMargin(); cbReflowInput->ComputedPhysicalPadding() = cbFrame->GetUsedPadding(); cbReflowInput->ComputedPhysicalBorderPadding() = cbFrame->GetUsedBorderAndPadding(); parentReflowInput.mCBReflowInput = cbReflowInput.ptr(); } NS_WARN_IF_FALSE(parentSize.ISize(parentWM) != NS_INTRINSICSIZE && parentSize.BSize(parentWM) != NS_INTRINSICSIZE, "parentSize should be valid"); parentReflowInput.SetComputedISize(std::max(parentSize.ISize(parentWM), 0)); parentReflowInput.SetComputedBSize(std::max(parentSize.BSize(parentWM), 0)); parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0); parentReflowInput.ComputedPhysicalPadding() = parentFrame->GetUsedPadding(); parentReflowInput.ComputedPhysicalBorderPadding() = parentFrame->GetUsedBorderAndPadding(); LogicalSize availSize = parentSize.ConvertTo(frameWM, parentWM); availSize.BSize(frameWM) = NS_INTRINSICSIZE; ViewportFrame* viewport = do_QueryFrame(parentFrame); nsSize cbSize = viewport ? viewport->AdjustReflowInputAsContainingBlock(&parentReflowInput).Size() : aFrame->GetContainingBlock()->GetSize(); const nsMargin& parentBorder = parentReflowInput.mStyleBorder->GetComputedBorder(); cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom()); LogicalSize lcbSize(frameWM, cbSize); ReflowInput reflowInput(aFrame->PresContext(), parentReflowInput, aFrame, availSize, &lcbSize); nsSize computedSize(reflowInput.ComputedWidth(), reflowInput.ComputedHeight()); computedSize.width += reflowInput.ComputedPhysicalBorderPadding().LeftRight(); if (computedSize.height != NS_INTRINSICSIZE) { computedSize.height += reflowInput.ComputedPhysicalBorderPadding().TopBottom(); } nsSize size = aFrame->GetSize(); // The RecomputePosition hint is not used if any offset changed between auto // and non-auto. If computedSize.height == NS_INTRINSICSIZE then the new // element height will be its intrinsic height, and since 'top' and 'bottom''s // auto-ness hasn't changed, the old height must also be its intrinsic // height, which we can assume hasn't changed (or reflow would have // been triggered). if (computedSize.width == size.width && (computedSize.height == NS_INTRINSICSIZE || computedSize.height == size.height)) { // If we're solving for 'left' or 'top', then compute it here, in order to // match the reflow code path. if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().left) { reflowInput.ComputedPhysicalOffsets().left = cbSize.width - reflowInput.ComputedPhysicalOffsets().right - reflowInput.ComputedPhysicalMargin().right - size.width - reflowInput.ComputedPhysicalMargin().left; } if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().top) { reflowInput.ComputedPhysicalOffsets().top = cbSize.height - reflowInput.ComputedPhysicalOffsets().bottom - reflowInput.ComputedPhysicalMargin().bottom - size.height - reflowInput.ComputedPhysicalMargin().top; } // Move the frame nsPoint pos(parentBorder.left + reflowInput.ComputedPhysicalOffsets().left + reflowInput.ComputedPhysicalMargin().left, parentBorder.top + reflowInput.ComputedPhysicalOffsets().top + reflowInput.ComputedPhysicalMargin().top); aFrame->SetPosition(pos); return true; } // Fall back to a reflow StyleChangeReflow(aFrame, nsChangeHint_NeedReflow); return false; }
void nsMathMLmrootFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); nsReflowStatus childStatus; mPresentationData.flags &= ~NS_MATHML_ERROR; aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); nsBoundingMetrics bmSqr, bmBase, bmIndex; DrawTarget* drawTarget = aReflowState.rendContext->GetDrawTarget(); ////////////////// // Reflow Children int32_t count = 0; nsIFrame* baseFrame = nullptr; nsIFrame* indexFrame = nullptr; nsHTMLReflowMetrics baseSize(aReflowState); nsHTMLReflowMetrics indexSize(aReflowState); nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { // ask our children to compute their bounding metrics nsHTMLReflowMetrics childDesiredSize(aReflowState, aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); WritingMode wm = childFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, childStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); if (0 == count) { // base baseFrame = childFrame; baseSize = childDesiredSize; bmBase = childDesiredSize.mBoundingMetrics; } else if (1 == count) { // index indexFrame = childFrame; indexSize = childDesiredSize; bmIndex = childDesiredSize.mBoundingMetrics; } count++; childFrame = childFrame->GetNextSibling(); } if (2 != count) { // report an error, encourage people to get their markups in order ReportChildCountError(); ReflowError(drawTarget, aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); // Call DidReflow() for the child frames we successfully did reflow. DidReflowChildren(mFrames.FirstChild(), childFrame); return; } //////////// // Prepare the radical symbol and the overline bar float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this); RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation); nscoord ruleThickness, leading, psi; GetRadicalParameters(fm, StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK, ruleThickness, leading, psi); // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131) char16_t one = '1'; nsBoundingMetrics bmOne = nsLayoutUtils::AppUnitBoundsOfString(&one, 1, *fm, drawTarget); if (bmOne.ascent > bmBase.ascent) psi += bmOne.ascent - bmBase.ascent; // make sure that the rule appears on on screen nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); if (ruleThickness < onePixel) { ruleThickness = onePixel; } // adjust clearance psi to get an exact number of pixels -- this // gives a nicer & uniform look on stacked radicals (bug 130282) nscoord delta = psi % onePixel; if (delta) psi += onePixel - delta; // round up // Stretch the radical symbol to the appropriate height if it is not big enough. nsBoundingMetrics contSize = bmBase; contSize.descent = bmBase.ascent + bmBase.descent + psi; contSize.ascent = ruleThickness; // height(radical) should be >= height(base) + psi + ruleThickness nsBoundingMetrics radicalSize; mSqrChar.Stretch(aPresContext, drawTarget, fontSizeInflation, NS_STRETCH_DIRECTION_VERTICAL, contSize, radicalSize, NS_STRETCH_LARGER, StyleVisibility()->mDirection); // radicalSize have changed at this point, and should match with // the bounding metrics of the char mSqrChar.GetBoundingMetrics(bmSqr); // Update the desired size for the container (like msqrt, index is not yet included) // the baseline will be that of the base. mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness; mBoundingMetrics.descent = std::max(bmBase.descent, (bmSqr.ascent + bmSqr.descent - mBoundingMetrics.ascent)); mBoundingMetrics.width = bmSqr.width + bmBase.width; mBoundingMetrics.leftBearing = bmSqr.leftBearing; mBoundingMetrics.rightBearing = bmSqr.width + std::max(bmBase.width, bmBase.rightBearing); // take also care of the rule aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading); aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + std::max(baseSize.Height() - baseSize.BlockStartAscent(), mBoundingMetrics.descent + ruleThickness); aDesiredSize.Width() = mBoundingMetrics.width; ///////////// // Re-adjust the desired size to include the index. // the index is raised by some fraction of the height // of the radical, see \mroot macro in App. B, TexBook float raiseIndexPercent = 0.6f; gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont(); if (mathFont) { raiseIndexPercent = mathFont->GetMathConstant(gfxFontEntry::RadicalDegreeBottomRaisePercent); } nscoord raiseIndexDelta = NSToCoordRound(raiseIndexPercent * (bmSqr.ascent + bmSqr.descent)); nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical - (bmSqr.ascent + bmSqr.descent) // to bottom of radical + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index nscoord indexClearance = 0; if (mBoundingMetrics.ascent < indexRaisedAscent) { indexClearance = indexRaisedAscent - mBoundingMetrics.ascent; // excess gap introduced by a tall index mBoundingMetrics.ascent = indexRaisedAscent; nscoord descent = aDesiredSize.Height() - aDesiredSize.BlockStartAscent(); aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading); aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + descent; } nscoord dxIndex, dxSqr; GetRadicalXOffsets(bmIndex.width, bmSqr.width, fm, &dxIndex, &dxSqr); mBoundingMetrics.width = dxSqr + bmSqr.width + bmBase.width; mBoundingMetrics.leftBearing = std::min(dxIndex + bmIndex.leftBearing, dxSqr + bmSqr.leftBearing); mBoundingMetrics.rightBearing = dxSqr + bmSqr.width + std::max(bmBase.width, bmBase.rightBearing); aDesiredSize.Width() = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; GatherAndStoreOverflow(&aDesiredSize); // place the index nscoord dx = dxIndex; nscoord dy = aDesiredSize.BlockStartAscent() - (indexRaisedAscent + indexSize.BlockStartAscent() - bmIndex.ascent); FinishReflowChild(indexFrame, aPresContext, indexSize, nullptr, MirrorIfRTL(aDesiredSize.Width(), indexSize.Width(), dx), dy, 0); // place the radical symbol and the radical bar dx = dxSqr; dy = indexClearance + leading; // leave a leading at the top mSqrChar.SetRect(nsRect(MirrorIfRTL(aDesiredSize.Width(), bmSqr.width, dx), dy, bmSqr.width, bmSqr.ascent + bmSqr.descent)); dx += bmSqr.width; mBarRect.SetRect(MirrorIfRTL(aDesiredSize.Width(), bmBase.width, dx), dy, bmBase.width, ruleThickness); // place the base dy = aDesiredSize.BlockStartAscent() - baseSize.BlockStartAscent(); FinishReflowChild(baseFrame, aPresContext, baseSize, nullptr, MirrorIfRTL(aDesiredSize.Width(), baseSize.Width(), dx), dy, 0); mReference.x = 0; mReference.y = aDesiredSize.BlockStartAscent(); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
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()); } }
void nsRangeFrame::ReflowAnonymousContent(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState) { // The width/height of our content box, which is the available width/height // for our anonymous content: nscoord rangeFrameContentBoxWidth = aReflowState.ComputedWidth(); nscoord rangeFrameContentBoxHeight = aReflowState.ComputedHeight(); if (rangeFrameContentBoxHeight == NS_AUTOHEIGHT) { rangeFrameContentBoxHeight = 0; } nsIFrame* trackFrame = mTrackDiv->GetPrimaryFrame(); if (trackFrame) { // display:none? // Position the track: // The idea here is that we allow content authors to style the width, // height, border and padding of the track, but we ignore margin and // positioning properties and do the positioning ourself to keep the center // of the track's border box on the center of the nsRangeFrame's content // box. WritingMode wm = trackFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState trackReflowState(aPresContext, aReflowState, trackFrame, availSize); // Find the x/y position of the track frame such that it will be positioned // as described above. These coordinates are with respect to the // nsRangeFrame's border-box. nscoord trackX = rangeFrameContentBoxWidth / 2; nscoord trackY = rangeFrameContentBoxHeight / 2; // Account for the track's border and padding (we ignore its margin): trackX -= trackReflowState.ComputedPhysicalBorderPadding().left + trackReflowState.ComputedWidth() / 2; trackY -= trackReflowState.ComputedPhysicalBorderPadding().top + trackReflowState.ComputedHeight() / 2; // Make relative to our border box instead of our content box: trackX += aReflowState.ComputedPhysicalBorderPadding().left; trackY += aReflowState.ComputedPhysicalBorderPadding().top; nsReflowStatus frameStatus; nsHTMLReflowMetrics trackDesiredSize(aReflowState); ReflowChild(trackFrame, aPresContext, trackDesiredSize, trackReflowState, trackX, trackY, 0, frameStatus); MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus), "We gave our child unconstrained height, so it should be complete"); FinishReflowChild(trackFrame, aPresContext, trackDesiredSize, &trackReflowState, trackX, trackY, 0); } nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame(); if (thumbFrame) { // display:none? WritingMode wm = thumbFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState thumbReflowState(aPresContext, aReflowState, thumbFrame, availSize); // Where we position the thumb depends on its size, so we first reflow // the thumb at {0,0} to obtain its size, then position it afterwards. nsReflowStatus frameStatus; nsHTMLReflowMetrics thumbDesiredSize(aReflowState); ReflowChild(thumbFrame, aPresContext, thumbDesiredSize, thumbReflowState, 0, 0, 0, frameStatus); MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus), "We gave our child unconstrained height, so it should be complete"); FinishReflowChild(thumbFrame, aPresContext, thumbDesiredSize, &thumbReflowState, 0, 0, 0); DoUpdateThumbPosition(thumbFrame, nsSize(aDesiredSize.Width(), aDesiredSize.Height())); } nsIFrame* rangeProgressFrame = mProgressDiv->GetPrimaryFrame(); if (rangeProgressFrame) { // display:none? WritingMode wm = rangeProgressFrame->GetWritingMode(); LogicalSize availSize = aReflowState.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; nsHTMLReflowState progressReflowState(aPresContext, aReflowState, rangeProgressFrame, availSize); // We first reflow the range-progress frame at {0,0} to obtain its // unadjusted dimensions, then we adjust it to so that the appropriate edge // ends at the thumb. nsReflowStatus frameStatus; nsHTMLReflowMetrics progressDesiredSize(aReflowState); ReflowChild(rangeProgressFrame, aPresContext, progressDesiredSize, progressReflowState, 0, 0, 0, frameStatus); MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus), "We gave our child unconstrained height, so it should be complete"); FinishReflowChild(rangeProgressFrame, aPresContext, progressDesiredSize, &progressReflowState, 0, 0, 0); DoUpdateRangeProgressFrame(rangeProgressFrame, nsSize(aDesiredSize.Width(), aDesiredSize.Height())); } }