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); }
/* 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 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(); }
bool nsColumnSetFrame::ReflowChildren(ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus, const ReflowConfig& aConfig, bool aUnboundedLastColumn, nsCollapsingMargin* aCarriedOutBEndMargin, ColumnBalanceData& aColData) { aColData.Reset(); bool allFit = true; WritingMode wm = GetWritingMode(); bool isVertical = wm.IsVertical(); bool isRTL = !wm.IsBidiLTR(); bool shrinkingBSizeOnly = !NS_SUBTREE_DIRTY(this) && mLastBalanceBSize > aConfig.mColMaxBSize; #ifdef DEBUG_roc printf("*** Doing column reflow pass: mLastBalanceBSize=%d, mColMaxBSize=%d, RTL=%d\n" " mBalanceColCount=%d, mColISize=%d, mColGap=%d\n", mLastBalanceBSize, aConfig.mColMaxBSize, isRTL, aConfig.mBalanceColCount, aConfig.mColISize, aConfig.mColGap); #endif DrainOverflowColumns(); const bool colBSizeChanged = mLastBalanceBSize != aConfig.mColMaxBSize; if (colBSizeChanged) { mLastBalanceBSize = aConfig.mColMaxBSize; // 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 LogicalMargin borderPadding = aReflowInput.ComputedLogicalBorderPadding(); borderPadding.ApplySkipSides(GetLogicalSkipSides(&aReflowInput)); nsRect contentRect(0, 0, 0, 0); nsOverflowAreas overflowRects; nsIFrame* child = mFrames.FirstChild(); LogicalPoint childOrigin(wm, borderPadding.IStart(wm), borderPadding.BStart(wm)); // In vertical-rl mode, columns will not be correctly placed if the // reflowInput's ComputedWidth() is UNCONSTRAINED (in which case we'll get // a containerSize.width of zero here). In that case, the column positions // will be adjusted later, after our correct contentSize is known. nsSize containerSize = aReflowInput.ComputedSizeAsContainerIfConstrained(); // For RTL, 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 // XXX when all of layout is converted to logical coordinates, we // probably won't need to do this hack any more. For now, we // confine it to the legacy horizontal-rl case if (!isVertical && isRTL) { nscoord availISize = aReflowInput.AvailableISize(); if (aReflowInput.ComputedISize() != NS_INTRINSICSIZE) { availISize = aReflowInput.ComputedISize(); } if (availISize != NS_INTRINSICSIZE) { childOrigin.I(wm) = containerSize.width - borderPadding.Left(wm) - availISize; #ifdef DEBUG_roc printf("*** childOrigin.iCoord = %d\n", childOrigin.I(wm)); #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 = !aReflowInput.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 skipResizeBSizeShrink = false; if (shrinkingBSizeOnly) { switch (wm.GetBlockDir()) { case WritingMode::eBlockTB: if (child->GetScrollableOverflowRect().YMost() <= aConfig.mColMaxBSize) { skipResizeBSizeShrink = true; } break; case WritingMode::eBlockLR: if (child->GetScrollableOverflowRect().XMost() <= aConfig.mColMaxBSize) { skipResizeBSizeShrink = true; } break; case WritingMode::eBlockRL: // XXX not sure how to handle this, so for now just don't attempt // the optimization break; default: NS_NOTREACHED("unknown block direction"); break; } } nscoord childContentBEnd = 0; if (!reflowNext && (skipIncremental || skipResizeBSizeShrink)) { // This child does not need to be reflowed, but we may need to move it MoveChildTo(child, childOrigin, wm, containerSize); // 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 block-size shrink %d): status = %d\n", columnCount, (void*)child, skipIncremental, skipResizeBSizeShrink, aStatus); #endif } else { LogicalSize availSize(wm, aConfig.mColISize, aConfig.mColMaxBSize); if (aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) { availSize.BSize(wm) = GetAvailableContentBSize(aReflowInput); } LogicalSize computedSize = aReflowInput.ComputedSize(wm); if (reflowNext) child->AddStateBits(NS_FRAME_IS_DIRTY); LogicalSize kidCBSize(wm, availSize.ISize(wm), computedSize.BSize(wm)); ReflowInput kidReflowInput(PresContext(), aReflowInput, child, availSize, &kidCBSize); kidReflowInput.mFlags.mIsTopOfPage = true; kidReflowInput.mFlags.mTableIsSplittable = false; kidReflowInput.mFlags.mIsColumnBalancing = aConfig.mBalanceColCount < INT32_MAX; // We need to reflow any float placeholders, even if our column height // hasn't changed. kidReflowInput.mFlags.mMustReflowPlaceholders = !colBSizeChanged; #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)) { kidReflowInput.mFlags.mNextInFlowUntouched = true; } ReflowOutput 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 LogicalPoint origin(wm, childOrigin.I(wm) + kidReflowInput.ComputedLogicalMargin().IStart(wm), childOrigin.B(wm) + kidReflowInput.ComputedLogicalMargin().BStart(wm)); ReflowChild(child, PresContext(), kidDesiredSize, kidReflowInput, wm, origin, containerSize, 0, aStatus); reflowNext = (aStatus & NS_FRAME_REFLOW_NEXTINFLOW) != 0; #ifdef DEBUG_roc printf("*** Reflowed child #%d %p: status = %d, desiredSize=%d,%d CarriedOutBEndMargin=%d\n", columnCount, (void*)child, aStatus, kidDesiredSize.Width(), kidDesiredSize.Height(), kidDesiredSize.mCarriedOutBEndMargin.get()); #endif NS_FRAME_TRACE_REFLOW_OUT("Column::Reflow", aStatus); *aCarriedOutBEndMargin = kidDesiredSize.mCarriedOutBEndMargin; FinishReflowChild(child, PresContext(), kidDesiredSize, &kidReflowInput, wm, childOrigin, containerSize, 0); childContentBEnd = nsLayoutUtils::CalculateContentBEnd(wm, child); if (childContentBEnd > aConfig.mColMaxBSize) { allFit = false; } if (childContentBEnd > availSize.BSize(wm)) { aColData.mMaxOverflowingBSize = std::max(childContentBEnd, aColData.mMaxOverflowingBSize); } } contentRect.UnionRect(contentRect, child->GetRect()); ConsiderChildOverflow(overflowRects, child); contentBEnd = std::max(contentBEnd, childContentBEnd); aColData.mLastBSize = childContentBEnd; aColData.mSumBSize += 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 kidNextInFlow = CreateNextInFlow(child); } // 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 > aReflowInput.ComputedMaxBSize() || contentBEnd > aReflowInput.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.mHasExcessBSize = 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) { childOrigin.I(wm) += aConfig.mColISize + aConfig.mColGap; #ifdef DEBUG_roc printf("*** NEXT CHILD ORIGIN.icoord = %d\n", childOrigin.I(wm)); #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.mMaxBSize = contentBEnd; LogicalSize contentSize = LogicalSize(wm, contentRect.Size()); contentSize.BSize(wm) = std::max(contentSize.BSize(wm), contentBEnd); mLastFrameStatus = aStatus; // Apply computed and min/max values if (aConfig.mComputedBSize != NS_INTRINSICSIZE) { if (aReflowInput.AvailableBSize() != NS_INTRINSICSIZE) { contentSize.BSize(wm) = std::min(contentSize.BSize(wm), aConfig.mComputedBSize); } else { contentSize.BSize(wm) = aConfig.mComputedBSize; } } else { // We add the "consumed" block-size back in so that we're applying // constraints to the correct bSize 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 bSize. but which // has prev-in-flows, trigger a larger bSize than actually required. contentSize.BSize(wm) = aReflowInput.ApplyMinMaxBSize(contentSize.BSize(wm), aConfig.mConsumedBSize); } if (aReflowInput.ComputedISize() != NS_INTRINSICSIZE) { contentSize.ISize(wm) = aReflowInput.ComputedISize(); } else { contentSize.ISize(wm) = aReflowInput.ApplyMinMaxISize(contentSize.ISize(wm)); } contentSize.ISize(wm) += borderPadding.IStartEnd(wm); contentSize.BSize(wm) += borderPadding.BStartEnd(wm); aDesiredSize.SetSize(wm, contentSize); aDesiredSize.mOverflowAreas = overflowRects; aDesiredSize.UnionOverflowAreasWithDesiredBounds(); // In vertical-rl mode, make a second pass if necessary to reposition the // columns with the correct container width. (In other writing modes, // correct containerSize was not required for column positioning so we don't // need this fixup.) if (wm.IsVerticalRL() && containerSize.width != contentSize.Width(wm)) { const nsSize finalContainerSize = aDesiredSize.PhysicalSize(); for (nsIFrame* child : mFrames) { // Get the logical position as set previously using a provisional or // dummy containerSize, and reset with the correct container size. child->SetPosition(wm, child->GetLogicalPosition(wm, containerSize), finalContainerSize); } } #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); }
nsresult nsTextControlFrame::CalcIntrinsicSize(nsRenderingContext* aRenderingContext, WritingMode aWM, LogicalSize& aIntrinsicSize, float aFontSizeInflation) { // Get leading and the Average/MaxAdvance char width nscoord lineHeight = 0; nscoord charWidth = 0; nscoord charMaxAdvance = 0; nsRefPtr<nsFontMetrics> fontMet; nsresult rv = nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet), aFontSizeInflation); NS_ENSURE_SUCCESS(rv, rv); lineHeight = nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(), NS_AUTOHEIGHT, aFontSizeInflation); charWidth = fontMet->AveCharWidth(); charMaxAdvance = fontMet->MaxAdvance(); // Set the width equal to the width in characters int32_t cols = GetCols(); aIntrinsicSize.ISize(aWM) = cols * charWidth; // To better match IE, take the maximum character width(in twips) and remove // 4 pixels add this on as additional padding(internalPadding). But only do // this if we think we have a fixed-width font. if (mozilla::Abs(charWidth - charMaxAdvance) > (unsigned)nsPresContext::CSSPixelsToAppUnits(1)) { nscoord internalPadding = std::max(0, charMaxAdvance - nsPresContext::CSSPixelsToAppUnits(4)); nscoord t = nsPresContext::CSSPixelsToAppUnits(1); // Round to a multiple of t nscoord rest = internalPadding % t; if (rest < t - rest) { internalPadding -= rest; } else { internalPadding += t - rest; } // Now add the extra padding on (so that small input sizes work well) aIntrinsicSize.ISize(aWM) += internalPadding; } else { // This is to account for the anonymous <br> having a 1 twip width // in Full Standards mode, see BRFrame::Reflow and bug 228752. if (PresContext()->CompatibilityMode() == eCompatibility_FullStandards) { aIntrinsicSize.ISize(aWM) += 1; } } // Increment width with cols * letter-spacing. { const nsStyleCoord& lsCoord = StyleText()->mLetterSpacing; if (eStyleUnit_Coord == lsCoord.GetUnit()) { nscoord letterSpacing = lsCoord.GetCoordValue(); if (letterSpacing != 0) { aIntrinsicSize.ISize(aWM) += cols * letterSpacing; } } } // Set the height equal to total number of rows (times the height of each // line, of course) aIntrinsicSize.BSize(aWM) = lineHeight * GetRows(); // Add in the size of the scrollbars for textarea if (IsTextArea()) { nsIFrame* first = GetFirstPrincipalChild(); nsIScrollableFrame *scrollableFrame = do_QueryFrame(first); NS_ASSERTION(scrollableFrame, "Child must be scrollable"); if (scrollableFrame) { nsMargin scrollbarSizes = scrollableFrame->GetDesiredScrollbarSizes(PresContext(), aRenderingContext); aIntrinsicSize.Width(aWM) += scrollbarSizes.LeftRight(); aIntrinsicSize.Height(aWM) += scrollbarSizes.TopBottom(); } } return NS_OK; }