/* virtual */ void nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // Although a ruby text container may have continuations, returning // NS_FRAME_COMPLETE here is still safe, since its parent, ruby frame, // ignores the status, and continuations of the ruby base container // will take care of our continuations. aStatus = NS_FRAME_COMPLETE; WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode(); nscoord minBCoord = nscoord_MAX; nscoord maxBCoord = nscoord_MIN; // The container size is not yet known, so we use a dummy (0, 0) size. // The block-dir position will be corrected below after containerSize // is finalized. const nsSize dummyContainerSize; for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) { nsIFrame* child = e.get(); MOZ_ASSERT(child->GetType() == nsGkAtoms::rubyTextFrame); LogicalRect rect = child->GetLogicalRect(lineWM, dummyContainerSize); LogicalMargin margin = child->GetLogicalUsedMargin(lineWM); nscoord blockStart = rect.BStart(lineWM) - margin.BStart(lineWM); minBCoord = std::min(minBCoord, blockStart); nscoord blockEnd = rect.BEnd(lineWM) + margin.BEnd(lineWM); maxBCoord = std::max(maxBCoord, blockEnd); } LogicalSize size(lineWM, mISize, 0); if (!mFrames.IsEmpty()) { if (MOZ_UNLIKELY(minBCoord > maxBCoord)) { // XXX When bug 765861 gets fixed, this warning should be upgraded. NS_WARNING("bad block coord"); minBCoord = maxBCoord = 0; } size.BSize(lineWM) = maxBCoord - minBCoord; nsSize containerSize = size.GetPhysicalSize(lineWM); for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) { nsIFrame* child = e.get(); // We reflowed the child with a dummy container size, as the true size // was not yet known at that time. LogicalPoint pos = child->GetLogicalPosition(lineWM, dummyContainerSize); // Adjust block position to account for minBCoord, // then reposition child based on the true container width. pos.B(lineWM) -= minBCoord; // Relative positioning hasn't happened yet. // So MovePositionBy should not be used here. child->SetPosition(lineWM, pos, containerSize); nsContainerFrame::PlaceFrameView(child); } } aDesiredSize.SetSize(lineWM, size); }
nscoord nsFloatManager::ClearFloats(WritingMode aWM, nscoord aBCoord, uint8_t aBreakType, nscoord aContainerWidth, uint32_t aFlags) const { if (!(aFlags & DONT_CLEAR_PUSHED_FLOATS) && ClearContinues(aBreakType)) { return nscoord_MAX; } if (!HasAnyFloats()) { return aBCoord; } LogicalPoint offset = mOffset.ConvertTo(aWM, mWritingMode, 0); nscoord blockEnd = aBCoord + offset.B(aWM); const FloatInfo &tail = mFloats[mFloats.Length() - 1]; switch (aBreakType) { case NS_STYLE_CLEAR_BOTH: blockEnd = std::max(blockEnd, tail.mLeftBEnd); blockEnd = std::max(blockEnd, tail.mRightBEnd); break; case NS_STYLE_CLEAR_LEFT: blockEnd = std::max(blockEnd, aWM.IsBidiLTR() ? tail.mLeftBEnd : tail.mRightBEnd); break; case NS_STYLE_CLEAR_RIGHT: blockEnd = std::max(blockEnd, aWM.IsBidiLTR() ? tail.mRightBEnd : tail.mLeftBEnd); break; default: // Do nothing break; } blockEnd -= offset.B(aWM); return blockEnd; }
nscoord nsFloatManager::GetLowestFloatTop(WritingMode aWM, nscoord aContainerWidth) const { if (mPushedLeftFloatPastBreak || mPushedRightFloatPastBreak) { return nscoord_MAX; } if (!HasAnyFloats()) { return nscoord_MIN; } FloatInfo fi = mFloats[mFloats.Length() - 1]; LogicalRect rect = fi.mRect.ConvertTo(aWM, fi.mWritingMode, aContainerWidth); LogicalPoint offset = mOffset.ConvertTo(aWM, mWritingMode, 0); return rect.BStart(aWM) - offset.B(aWM); }
LogicalRect nsGridContainerFrame::ContainingBlockForAbsPos( const WritingMode& aWM, const GridArea& aArea, const nsTArray<TrackSize>& aColSizes, const nsTArray<TrackSize>& aRowSizes, const LogicalPoint& aGridOrigin, const LogicalRect& aGridCB) const { nscoord i = aGridCB.IStart(aWM); nscoord b = aGridCB.BStart(aWM); nscoord iSize = aGridCB.ISize(aWM); nscoord bSize = aGridCB.BSize(aWM); aArea.mCols.ToPositionAndLengthForAbsPos(aColSizes, aGridOrigin.I(aWM), &i, &iSize); aArea.mRows.ToPositionAndLengthForAbsPos(aRowSizes, aGridOrigin.B(aWM), &b, &bSize); return LogicalRect(aWM, i, b, iSize, bSize); }
nsFlowAreaRect nsFloatManager::GetFlowArea(WritingMode aWM, nscoord aBOffset, BandInfoType aInfoType, nscoord aBSize, LogicalRect aContentArea, SavedState* aState, nscoord aContainerWidth) const { NS_ASSERTION(aBSize >= 0, "unexpected max block size"); NS_ASSERTION(aContentArea.ISize(aWM) >= 0, "unexpected content area inline size"); LogicalPoint offset = mOffset.ConvertTo(aWM, mWritingMode, 0); nscoord blockStart = aBOffset + offset.B(aWM); if (blockStart < nscoord_MIN) { NS_WARNING("bad value"); blockStart = nscoord_MIN; } // Determine the last float that we should consider. uint32_t floatCount; if (aState) { // Use the provided state. floatCount = aState->mFloatInfoCount; NS_ABORT_IF_FALSE(floatCount <= mFloats.Length(), "bad state"); } else { // Use our current state. floatCount = mFloats.Length(); } // If there are no floats at all, or we're below the last one, return // quickly. if (floatCount == 0 || (mFloats[floatCount-1].mLeftBEnd <= blockStart && mFloats[floatCount-1].mRightBEnd <= blockStart)) { return nsFlowAreaRect(aWM, aContentArea.IStart(aWM), aBOffset, aContentArea.ISize(aWM), aBSize, false); } nscoord blockEnd; if (aBSize == nscoord_MAX) { // This warning (and the two below) are possible to hit on pages // with really large objects. NS_WARN_IF_FALSE(aInfoType == BAND_FROM_POINT, "bad height"); blockEnd = nscoord_MAX; } else { blockEnd = blockStart + aBSize; if (blockEnd < blockStart || blockEnd > nscoord_MAX) { NS_WARNING("bad value"); blockEnd = nscoord_MAX; } } nscoord inlineStart = offset.I(aWM) + aContentArea.IStart(aWM); nscoord inlineEnd = offset.I(aWM) + aContentArea.IEnd(aWM); if (inlineEnd < inlineStart) { NS_WARNING("bad value"); inlineEnd = inlineStart; } // Walk backwards through the floats until we either hit the front of // the list or we're above |blockStart|. bool haveFloats = false; for (uint32_t i = floatCount; i > 0; --i) { const FloatInfo &fi = mFloats[i-1]; if (fi.mLeftBEnd <= blockStart && fi.mRightBEnd <= blockStart) { // There aren't any more floats that could intersect this band. break; } if (fi.mRect.IsEmpty()) { // For compatibility, ignore floats with empty rects, even though it // disagrees with the spec. (We might want to fix this in the // future, though.) continue; } LogicalRect rect = fi.mRect.ConvertTo(aWM, fi.mWritingMode, aContainerWidth); nscoord floatBStart = rect.BStart(aWM); nscoord floatBEnd = rect.BEnd(aWM); if (blockStart < floatBStart && aInfoType == BAND_FROM_POINT) { // This float is below our band. Shrink our band's height if needed. if (floatBStart < blockEnd) { blockEnd = floatBStart; } } // If blockStart == blockEnd (which happens only with WIDTH_WITHIN_HEIGHT), // we include floats that begin at our 0-height vertical area. We // need to to this to satisfy the invariant that a // WIDTH_WITHIN_HEIGHT call is at least as narrow on both sides as a // BAND_WITHIN_POINT call beginning at its blockStart. else if (blockStart < floatBEnd && (floatBStart < blockEnd || (floatBStart == blockEnd && blockStart == blockEnd))) { // This float is in our band. // Shrink our band's height if needed. if (floatBEnd < blockEnd && aInfoType == BAND_FROM_POINT) { blockEnd = floatBEnd; } // Shrink our band's width if needed. if ((fi.mFrame->StyleDisplay()->mFloats == NS_STYLE_FLOAT_LEFT) == aWM.IsBidiLTR()) { // A left float in an ltr block or a right float in an rtl block nscoord inlineEndEdge = rect.IEnd(aWM); if (inlineEndEdge > inlineStart) { inlineStart = inlineEndEdge; // Only set haveFloats to true if the float is inside our // containing block. This matches the spec for what some // callers want and disagrees for other callers, so we should // probably provide better information at some point. haveFloats = true; } } else { // A left float in an rtl block or a right float in an ltr block nscoord inlineStartEdge = rect.IStart(aWM); if (inlineStartEdge < inlineEnd) { inlineEnd = inlineStartEdge; // See above. haveFloats = true; } } } } nscoord blockSize = (blockEnd == nscoord_MAX) ? nscoord_MAX : (blockEnd - blockStart); return nsFlowAreaRect(aWM, inlineStart - offset.I(aWM), blockStart - offset.B(aWM), inlineEnd - inlineStart, blockSize, haveFloats); }
void nsGridContainerFrame::ReflowChildren(GridItemCSSOrderIterator& aIter, const LogicalRect& aContentArea, const nsTArray<TrackSize>& aColSizes, const nsTArray<TrackSize>& aRowSizes, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { WritingMode wm = aReflowState.GetWritingMode(); const LogicalPoint gridOrigin(aContentArea.Origin(wm)); const nscoord gridWidth = aContentArea.Width(wm); nsPresContext* pc = PresContext(); for (; !aIter.AtEnd(); aIter.Next()) { nsIFrame* child = *aIter; GridArea* area = GetGridAreaForChild(child); MOZ_ASSERT(area && area->IsDefinite()); LogicalRect cb = ContainingBlockFor(wm, *area, aColSizes, aRowSizes); cb += gridOrigin; nsHTMLReflowState childRS(pc, aReflowState, child, cb.Size(wm)); const LogicalMargin margin = childRS.ComputedLogicalMargin(); if (childRS.ComputedBSize() == NS_AUTOHEIGHT) { // XXX the start of an align-self:stretch impl. Needs min-/max-bsize // clamping though, and check the prop value is actually 'stretch'! LogicalMargin bp = childRS.ComputedLogicalBorderPadding(); bp.ApplySkipSides(child->GetLogicalSkipSides()); nscoord bSize = cb.BSize(wm) - bp.BStartEnd(wm) - margin.BStartEnd(wm); childRS.SetComputedBSize(std::max(bSize, 0)); } LogicalPoint childPos = cb.Origin(wm); childPos.I(wm) += margin.IStart(wm); childPos.B(wm) += margin.BStart(wm); nsHTMLReflowMetrics childSize(childRS); nsReflowStatus childStatus; ReflowChild(child, pc, childSize, childRS, wm, childPos, gridWidth, 0, childStatus); FinishReflowChild(child, pc, childSize, &childRS, wm, childPos, gridWidth, 0); ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child); // XXX deal with 'childStatus' not being COMPLETE } if (IsAbsoluteContainer()) { nsFrameList children(GetChildList(GetAbsoluteListID())); if (!children.IsEmpty()) { LogicalMargin pad(aReflowState.ComputedLogicalPadding()); pad.ApplySkipSides(GetLogicalSkipSides(&aReflowState)); // 'gridOrigin' is the origin of the grid (the start of the first track), // with respect to the grid container's padding-box (CB). const LogicalPoint gridOrigin(wm, pad.IStart(wm), pad.BStart(wm)); const LogicalRect gridCB(wm, 0, 0, aContentArea.ISize(wm) + pad.IStartEnd(wm), aContentArea.BSize(wm) + pad.BStartEnd(wm)); for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) { nsIFrame* child = e.get(); GridArea* area = GetGridAreaForChild(child); MOZ_ASSERT(area); LogicalRect itemCB(ContainingBlockForAbsPos(wm, *area, aColSizes, aRowSizes, gridOrigin, gridCB)); // nsAbsoluteContainingBlock::Reflow uses physical coordinates. nsRect* cb = static_cast<nsRect*>(child->Properties().Get( GridItemContainingBlockRect())); if (!cb) { cb = new nsRect; child->Properties().Set(GridItemContainingBlockRect(), cb); } *cb = itemCB.GetPhysicalRect(wm, gridWidth); } // This rect isn't used at all for layout so we use it to optimize // away the virtual GetType() call in the callee in most cases. // @see nsAbsoluteContainingBlock::Reflow nsRect dummyRect(0, 0, VERY_LIKELY_A_GRID_CONTAINER, 0); GetAbsoluteContainingBlock()->Reflow(this, pc, aReflowState, aStatus, dummyRect, true, true, true, // XXX could be optimized &aDesiredSize.mOverflowAreas); } } }
nsresult nsTableWrapperFrame::GetInnerOrigin(uint32_t aCaptionSide, const LogicalSize& aContainBlockSize, const LogicalSize& aCaptionSize, const LogicalMargin& aCaptionMargin, const LogicalSize& aInnerSize, LogicalMargin& aInnerMargin, LogicalPoint& aOrigin, WritingMode aWM) { NS_ASSERTION(NS_AUTOMARGIN != aCaptionMargin.IStart(aWM) && NS_AUTOMARGIN != aCaptionMargin.IEnd(aWM), "The computed caption margin is auto?"); NS_ASSERTION(NS_AUTOMARGIN != aInnerMargin.IStart(aWM) && NS_AUTOMARGIN != aInnerMargin.IEnd(aWM) && NS_AUTOMARGIN != aInnerMargin.BStart(aWM) && NS_AUTOMARGIN != aInnerMargin.BEnd(aWM), "The computed inner margin is auto?"); aOrigin.I(aWM) = aOrigin.B(aWM) = 0; if ((NS_UNCONSTRAINEDSIZE == aInnerSize.ISize(aWM)) || (NS_UNCONSTRAINEDSIZE == aInnerSize.BSize(aWM)) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.ISize(aWM)) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.BSize(aWM))) { return NS_OK; } nscoord minCapISize = aCaptionSize.ISize(aWM) + aCaptionMargin.IStartEnd(aWM); // inline-dir computation switch (aCaptionSide) { case NS_STYLE_CAPTION_SIDE_LEFT: case NS_STYLE_CAPTION_SIDE_RIGHT: if (aWM.IsBidiLTR() == (aCaptionSide == NS_STYLE_CAPTION_SIDE_LEFT)) { if (aInnerMargin.IStart(aWM) < minCapISize) { // shift the inner table to get some place for the caption aInnerMargin.IEnd(aWM) += aInnerMargin.IStart(aWM) - minCapISize; aInnerMargin.IEnd(aWM) = std::max(0, aInnerMargin.IEnd(aWM)); aInnerMargin.IStart(aWM) = minCapISize; } } aOrigin.I(aWM) = aInnerMargin.IStart(aWM); break; default: NS_ASSERTION(aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP || aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE || aCaptionSide == NS_STYLE_CAPTION_SIDE_BOTTOM || aCaptionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE || aCaptionSide == NO_SIDE, "unexpected caption side"); aOrigin.I(aWM) = aInnerMargin.IStart(aWM); break; } // block-dir computation switch (aCaptionSide) { case NS_STYLE_CAPTION_SIDE_BOTTOM: case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE: aOrigin.B(aWM) = aInnerMargin.BStart(aWM); break; case NS_STYLE_CAPTION_SIDE_LEFT: case NS_STYLE_CAPTION_SIDE_RIGHT: aOrigin.B(aWM) = aInnerMargin.BStart(aWM); switch (GetCaptionVerticalAlign()) { case NS_STYLE_VERTICAL_ALIGN_MIDDLE: aOrigin.B(aWM) = std::max(aInnerMargin.BStart(aWM), (aCaptionSize.BSize(aWM) - aInnerSize.BSize(aWM)) / 2); break; case NS_STYLE_VERTICAL_ALIGN_BOTTOM: aOrigin.B(aWM) = std::max(aInnerMargin.BStart(aWM), aCaptionSize.BSize(aWM) - aInnerSize.BSize(aWM)); break; default: break; } break; case NO_SIDE: case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE: case NS_STYLE_CAPTION_SIDE_TOP: aOrigin.B(aWM) = aInnerMargin.BStart(aWM) + aCaptionSize.BSize(aWM) + aCaptionMargin.BStartEnd(aWM); break; default: NS_NOTREACHED("Unknown caption alignment type"); break; } return NS_OK; }
nsresult nsTableWrapperFrame::GetCaptionOrigin(uint32_t aCaptionSide, const LogicalSize& aContainBlockSize, const LogicalSize& aInnerSize, const LogicalMargin& aInnerMargin, const LogicalSize& aCaptionSize, LogicalMargin& aCaptionMargin, LogicalPoint& aOrigin, WritingMode aWM) { aOrigin.I(aWM) = aOrigin.B(aWM) = 0; if ((NS_UNCONSTRAINEDSIZE == aInnerSize.ISize(aWM)) || (NS_UNCONSTRAINEDSIZE == aInnerSize.BSize(aWM)) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.ISize(aWM)) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.BSize(aWM))) { return NS_OK; } if (mCaptionFrames.IsEmpty()) { return NS_OK; } NS_ASSERTION(NS_AUTOMARGIN != aCaptionMargin.IStart(aWM) && NS_AUTOMARGIN != aCaptionMargin.BStart(aWM) && NS_AUTOMARGIN != aCaptionMargin.BEnd(aWM), "The computed caption margin is auto?"); // inline-dir computation switch (aCaptionSide) { case NS_STYLE_CAPTION_SIDE_BOTTOM: case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE: aOrigin.I(aWM) = aCaptionMargin.IStart(aWM); if (aCaptionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) { // We placed the caption using only the table's isize as available // isize, and we should position it this way as well. aOrigin.I(aWM) += aInnerMargin.IStart(aWM); } break; case NS_STYLE_CAPTION_SIDE_LEFT: case NS_STYLE_CAPTION_SIDE_RIGHT: aOrigin.I(aWM) = aCaptionMargin.IStart(aWM); if (aWM.IsBidiLTR() == (aCaptionSide == NS_STYLE_CAPTION_SIDE_RIGHT)) { aOrigin.I(aWM) += aInnerMargin.IStart(aWM) + aInnerSize.ISize(aWM); } break; default: // block-start NS_ASSERTION(aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP || aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE, "unexpected caption side"); aOrigin.I(aWM) = aCaptionMargin.IStart(aWM); if (aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP) { // We placed the caption using only the table's isize as available // isize, and we should position it this way as well. aOrigin.I(aWM) += aInnerMargin.IStart(aWM); } break; } // block-dir computation switch (aCaptionSide) { case NS_STYLE_CAPTION_SIDE_RIGHT: case NS_STYLE_CAPTION_SIDE_LEFT: aOrigin.B(aWM) = aInnerMargin.BStart(aWM); switch (GetCaptionVerticalAlign()) { case NS_STYLE_VERTICAL_ALIGN_MIDDLE: aOrigin.B(aWM) = std::max(0, aInnerMargin.BStart(aWM) + ((aInnerSize.BSize(aWM) - aCaptionSize.BSize(aWM)) / 2)); break; case NS_STYLE_VERTICAL_ALIGN_BOTTOM: aOrigin.B(aWM) = std::max(0, aInnerMargin.BStart(aWM) + aInnerSize.BSize(aWM) - aCaptionSize.BSize(aWM)); break; default: break; } break; case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE: case NS_STYLE_CAPTION_SIDE_BOTTOM: aOrigin.B(aWM) = aInnerMargin.BStart(aWM) + aInnerSize.BSize(aWM) + aCaptionMargin.BStart(aWM); break; case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE: case NS_STYLE_CAPTION_SIDE_TOP: aOrigin.B(aWM) = aInnerMargin.BStart(aWM) + aCaptionMargin.BStart(aWM); break; default: NS_NOTREACHED("Unknown caption alignment type"); break; } return NS_OK; }