nsresult nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame, nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nscoord aContainingBlockWidth, nscoord aContainingBlockHeight, PRBool aConstrainHeight, nsIFrame* aKidFrame, nsReflowStatus& aStatus, nsOverflowAreas* aOverflowAreas) { #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent); printf("abs pos "); if (aKidFrame) { nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); } char width[16]; char height[16]; PrettyUC(aReflowState.availableWidth, width); PrettyUC(aReflowState.availableHeight, height); printf(" a=%s,%s ", width, height); PrettyUC(aReflowState.ComputedWidth(), width); PrettyUC(aReflowState.ComputedHeight(), height); printf("c=%s,%s \n", width, height); } AutoNoisyIndenter indent(nsBlockFrame::gNoisy); #endif // DEBUG // Store position and overflow rect so taht we can invalidate the correct // area if the position changes nsRect oldOverflowRect(aKidFrame->GetVisualOverflowRect() + aKidFrame->GetPosition()); nsRect oldRect = aKidFrame->GetRect(); nsresult rv; // Get the border values const nsMargin& border = aReflowState.mStyleBorder->GetActualBorder(); nscoord availWidth = aContainingBlockWidth; if (availWidth == -1) { NS_ASSERTION(aReflowState.ComputedWidth() != NS_UNCONSTRAINEDSIZE, "Must have a useful width _somewhere_"); availWidth = aReflowState.ComputedWidth() + aReflowState.mComputedPadding.LeftRight(); } nsHTMLReflowMetrics kidDesiredSize; nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame, nsSize(availWidth, NS_UNCONSTRAINEDSIZE), aContainingBlockWidth, aContainingBlockHeight); // Send the WillReflow() notification and position the frame aKidFrame->WillReflow(aPresContext); PRBool constrainHeight = (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) && aConstrainHeight // Don't split if told not to (e.g. for fixed frames) && (aDelegatingFrame->GetType() != nsGkAtoms::positionedInlineFrame) //XXX we don't handle splitting frames for inline absolute containing blocks yet && (aKidFrame->GetRect().y <= aReflowState.availableHeight); // Don't split things below the fold. (Ideally we shouldn't *have* // anything totally below the fold, but we can't position frames // across next-in-flow breaks yet. if (constrainHeight) { kidReflowState.availableHeight = aReflowState.availableHeight - border.top - kidReflowState.mComputedMargin.top; if (NS_AUTOOFFSET != kidReflowState.mComputedOffsets.top) kidReflowState.availableHeight -= kidReflowState.mComputedOffsets.top; } // Do the reflow rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); // If we're solving for 'left' or 'top', then compute it now that we know the // width/height if ((NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left) || (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top)) { if (-1 == aContainingBlockWidth) { // Get the containing block width/height kidReflowState.ComputeContainingBlockRectangle(aPresContext, &aReflowState, aContainingBlockWidth, aContainingBlockHeight); } if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left) { NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.mComputedOffsets.right, "Can't solve for both left and right"); kidReflowState.mComputedOffsets.left = aContainingBlockWidth - kidReflowState.mComputedOffsets.right - kidReflowState.mComputedMargin.right - kidDesiredSize.width - kidReflowState.mComputedMargin.left; } if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top) { kidReflowState.mComputedOffsets.top = aContainingBlockHeight - kidReflowState.mComputedOffsets.bottom - kidReflowState.mComputedMargin.bottom - kidDesiredSize.height - kidReflowState.mComputedMargin.top; } } // Position the child relative to our padding edge nsRect rect(border.left + kidReflowState.mComputedOffsets.left + kidReflowState.mComputedMargin.left, border.top + kidReflowState.mComputedOffsets.top + kidReflowState.mComputedMargin.top, kidDesiredSize.width, kidDesiredSize.height); aKidFrame->SetRect(rect); nsIView* 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); } if (oldRect.TopLeft() != rect.TopLeft() || (aDelegatingFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // The frame moved aKidFrame->GetParent()->Invalidate(oldOverflowRect); aKidFrame->InvalidateFrameSubtree(); } else if (oldRect.Size() != rect.Size()) { // Invalidate the area where the frame changed size. nscoord innerWidth = NS_MIN(oldRect.width, rect.width); nscoord innerHeight = NS_MIN(oldRect.height, rect.height); nscoord outerWidth = NS_MAX(oldRect.width, rect.width); nscoord outerHeight = NS_MAX(oldRect.height, rect.height); aKidFrame->GetParent()->Invalidate( nsRect(rect.x + innerWidth, rect.y, outerWidth - innerWidth, outerHeight)); // Invalidate the horizontal strip aKidFrame->GetParent()->Invalidate( nsRect(rect.x, rect.y + innerHeight, outerWidth, outerHeight - innerHeight)); } aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED); #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1); printf("abs pos "); if (aKidFrame) { nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); } printf("%p rect=%d,%d,%d,%d\n", static_cast<void*>(aKidFrame), rect.x, rect.y, rect.width, rect.height); } #endif if (aOverflowAreas) { aOverflowAreas->UnionWith(kidDesiredSize.mOverflowAreas + rect.TopLeft()); } return rv; }
void nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame, nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, const nsRect& aContainingBlock, bool aConstrainHeight, nsIFrame* aKidFrame, nsReflowStatus& aStatus, nsOverflowAreas* aOverflowAreas) { #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent); printf("abs pos "); if (aKidFrame) { nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); } char width[16]; char height[16]; PrettyUC(aReflowState.AvailableWidth(), width); PrettyUC(aReflowState.AvailableHeight(), height); printf(" a=%s,%s ", width, height); PrettyUC(aReflowState.ComputedWidth(), width); PrettyUC(aReflowState.ComputedHeight(), height); printf("c=%s,%s \n", width, height); } AutoNoisyIndenter indent(nsBlockFrame::gNoisy); #endif // DEBUG nscoord availWidth = aContainingBlock.width; if (availWidth == -1) { NS_ASSERTION(aReflowState.ComputedWidth() != NS_UNCONSTRAINEDSIZE, "Must have a useful width _somewhere_"); availWidth = aReflowState.ComputedWidth() + aReflowState.ComputedPhysicalPadding().LeftRight(); } nsHTMLReflowMetrics kidDesiredSize(aReflowState); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame, nsSize(availWidth, NS_UNCONSTRAINEDSIZE), aContainingBlock.width, aContainingBlock.height); // Send the WillReflow() notification and position the frame aKidFrame->WillReflow(aPresContext); // Get the border values const nsMargin& border = aReflowState.mStyleBorder->GetComputedBorder(); bool constrainHeight = (aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE) && aConstrainHeight // Don't split if told not to (e.g. for fixed frames) && (aDelegatingFrame->GetType() != nsGkAtoms::inlineFrame) //XXX we don't handle splitting frames for inline absolute containing blocks yet && (aKidFrame->GetRect().y <= aReflowState.AvailableHeight()); // Don't split things below the fold. (Ideally we shouldn't *have* // anything totally below the fold, but we can't position frames // across next-in-flow breaks yet. if (constrainHeight) { kidReflowState.AvailableHeight() = aReflowState.AvailableHeight() - border.top - kidReflowState.ComputedPhysicalMargin().top; if (NS_AUTOOFFSET != kidReflowState.ComputedPhysicalOffsets().top) kidReflowState.AvailableHeight() -= kidReflowState.ComputedPhysicalOffsets().top; } // Do the reflow aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); // If we're solving for 'left' or 'top', then compute it now that we know the // width/height if ((NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().left) || (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().top)) { nscoord aContainingBlockWidth = aContainingBlock.width; nscoord aContainingBlockHeight = aContainingBlock.height; if (-1 == aContainingBlockWidth) { // Get the containing block width/height kidReflowState.ComputeContainingBlockRectangle(aPresContext, &aReflowState, aContainingBlockWidth, aContainingBlockHeight); } if (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().left) { NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.ComputedPhysicalOffsets().right, "Can't solve for both left and right"); kidReflowState.ComputedPhysicalOffsets().left = aContainingBlockWidth - kidReflowState.ComputedPhysicalOffsets().right - kidReflowState.ComputedPhysicalMargin().right - kidDesiredSize.Width() - kidReflowState.ComputedPhysicalMargin().left; } if (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().top) { kidReflowState.ComputedPhysicalOffsets().top = aContainingBlockHeight - kidReflowState.ComputedPhysicalOffsets().bottom - kidReflowState.ComputedPhysicalMargin().bottom - kidDesiredSize.Height() - kidReflowState.ComputedPhysicalMargin().top; } } // Position the child relative to our padding edge nsRect rect(border.left + kidReflowState.ComputedPhysicalOffsets().left + kidReflowState.ComputedPhysicalMargin().left, border.top + kidReflowState.ComputedPhysicalOffsets().top + kidReflowState.ComputedPhysicalMargin().top, kidDesiredSize.Width(), kidDesiredSize.Height()); // Offset the frame rect by the given origin of the absolute containing block. // If the frame is auto-positioned on both sides of an axis, it will be // positioned based on its containing block and we don't need to offset. if (aContainingBlock.TopLeft() != nsPoint(0, 0)) { if (!(kidReflowState.mStylePosition->mOffset.GetLeftUnit() == eStyleUnit_Auto && kidReflowState.mStylePosition->mOffset.GetRightUnit() == eStyleUnit_Auto)) { rect.x += aContainingBlock.x; } if (!(kidReflowState.mStylePosition->mOffset.GetTopUnit() == eStyleUnit_Auto && kidReflowState.mStylePosition->mOffset.GetBottomUnit() == eStyleUnit_Auto)) { rect.y += aContainingBlock.y; } } aKidFrame->SetRect(rect); nsView* view = aKidFrame->GetView(); if (view) { // Size and position the view and set its opacity, visibility, content // transparency, and clip nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aKidFrame, view, kidDesiredSize.VisualOverflow()); } else { nsContainerFrame::PositionChildViews(aKidFrame); } aKidFrame->DidReflow(aPresContext, &kidReflowState, nsDidReflowStatus::FINISHED); #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1); printf("abs pos "); if (aKidFrame) { nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); } printf("%p rect=%d,%d,%d,%d\n", static_cast<void*>(aKidFrame), rect.x, rect.y, rect.width, rect.height); } #endif if (aOverflowAreas) { aOverflowAreas->UnionWith(kidDesiredSize.mOverflowAreas + rect.TopLeft()); } }