Bug 307158. Half-heartedly account for vertical scrollbar presence when positioning absolute children relative to the right edge of a scrollable container. r+sr=dbaron with regrets.

This commit is contained in:
roc+%cs.cmu.edu 2005-10-18 05:00:24 +00:00
Родитель 6729b6e9ae
Коммит 49188025d3
6 изменённых файлов: 59 добавлений и 13 удалений

Просмотреть файл

@ -75,10 +75,12 @@
#include "nsLayoutErrors.h"
#include "nsAutoPtr.h"
#include "nsIServiceManager.h"
#include "nsIScrollableFrame.h"
#ifdef ACCESSIBILITY
#include "nsIAccessibilityService.h"
#endif
#include "nsLayoutUtils.h"
#include "nsBoxLayoutState.h"
#ifdef IBMBIDI
#include "nsBidiPresUtils.h"
@ -601,8 +603,10 @@ CalculateContainingBlockSizeForAbsolutes(const nsHTMLReflowState& aReflowState,
// First, find the reflow state for the outermost frame for this
// content.
const nsHTMLReflowState* aLastRS = &aReflowState;
const nsHTMLReflowState* lastButOneRS = &aReflowState;
while (aLastRS->parentReflowState &&
aLastRS->parentReflowState->frame->GetContent() == frame->GetContent()) {
lastButOneRS = aLastRS;
aLastRS = aLastRS->parentReflowState;
}
if (aLastRS != &aReflowState) {
@ -610,13 +614,34 @@ CalculateContainingBlockSizeForAbsolutes(const nsHTMLReflowState& aReflowState,
// heck did it end up wrapping this block frame?
NS_ASSERTION(aLastRS->frame->GetStyleDisplay()->IsBlockLevel(),
"Wrapping frame should be block-level");
// Scrollbars need to be specifically excluded, if present, because they are outside the
// padding-edge. We need better APIs for getting the various boxes from a frame.
nsIScrollableFrame* scrollFrame;
CallQueryInterface(aLastRS->frame, &scrollFrame);
nsMargin scrollbars(0,0,0,0);
if (scrollFrame) {
nsBoxLayoutState dummyState(aLastRS->frame->GetPresContext());
scrollbars = scrollFrame->GetDesiredScrollbarSizes(&dummyState);
// XXX We should account for the horizontal scrollbar too --- but currently
// nsGfxScrollFrame assumes nothing depends on the presence (or absence) of
// a horizontal scrollbar, so accounting for it would create incremental
// reflow bugs.
//if (!lastButOneRS->mFlags.mAssumingHScrollbar) {
scrollbars.top = scrollbars.bottom = 0;
//}
if (!lastButOneRS->mFlags.mAssumingVScrollbar) {
scrollbars.left = scrollbars.right = 0;
}
}
// We found a reflow state for the outermost wrapping frame, so use
// its computed metrics if available
if (aLastRS->mComputedWidth != NS_UNCONSTRAINEDSIZE) {
cbSize.width = aLastRS->mComputedWidth + aLastRS->mComputedPadding.LeftRight();
cbSize.width = PR_MAX(0,
aLastRS->mComputedWidth + aLastRS->mComputedPadding.LeftRight() - scrollbars.LeftRight());
}
if (aLastRS->mComputedHeight != NS_UNCONSTRAINEDSIZE) {
cbSize.height = aLastRS->mComputedHeight + aLastRS->mComputedPadding.TopBottom();
cbSize.height = PR_MAX(0,
aLastRS->mComputedHeight + aLastRS->mComputedPadding.TopBottom() - scrollbars.TopBottom());
}
}
}

Просмотреть файл

@ -472,6 +472,7 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowState* aState,
nsresult
nsHTMLScrollFrame::ReflowScrolledFrame(const ScrollReflowState& aState,
PRBool aAssumeHScroll,
PRBool aAssumeVScroll,
nsHTMLReflowMetrics* aMetrics,
PRBool aFirstPass)
@ -509,6 +510,8 @@ nsHTMLScrollFrame::ReflowScrolledFrame(const ScrollReflowState& aState,
mInner.mScrolledFrame,
nsSize(availWidth, NS_UNCONSTRAINEDSIZE),
aFirstPass ? aState.mNewReason : eReflowReason_Resize);
kidReflowState.mFlags.mAssumingHScrollbar = aAssumeHScroll;
kidReflowState.mFlags.mAssumingVScrollbar = aAssumeVScroll;
if (IsRTLTextControl()) {
kidReflowState.mRightEdge = mInner.GetScrolledSize().width;
@ -585,7 +588,7 @@ nsHTMLScrollFrame::ReflowContents(ScrollReflowState* aState,
{
PRBool currentlyUsingVScrollbar = GuessVScrollbarNeeded(*aState);
nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags);
nsresult rv = ReflowScrolledFrame(*aState, currentlyUsingVScrollbar,
nsresult rv = ReflowScrolledFrame(*aState, PR_FALSE, currentlyUsingVScrollbar,
&kidDesiredSize, PR_TRUE);
if (NS_FAILED(rv))
return rv;
@ -617,7 +620,7 @@ nsHTMLScrollFrame::ReflowContents(ScrollReflowState* aState,
kidDesiredSize.mOverflowArea.YMost() <= insideBorderSize.height) {
// Let's pretend we had no vertical scrollbar coming in here
currentlyUsingVScrollbar = PR_FALSE;
rv = ReflowScrolledFrame(*aState, currentlyUsingVScrollbar,
rv = ReflowScrolledFrame(*aState, PR_FALSE, currentlyUsingVScrollbar,
&kidDesiredSize, PR_FALSE);
if (NS_FAILED(rv))
return rv;
@ -628,6 +631,9 @@ nsHTMLScrollFrame::ReflowContents(ScrollReflowState* aState,
// First try a layout without a horizontal scrollbar, then with.
if (TryLayout(aState, kidDesiredSize, didUseScrollbar, PR_FALSE, PR_FALSE))
return NS_OK;
// XXX Adding a horizontal scrollbar could cause absolute children positioned
// relative to the bottom padding-edge to need to be reflowed. But we don't,
// because that would be slow.
if (TryLayout(aState, kidDesiredSize, didUseScrollbar, PR_TRUE, PR_FALSE))
return NS_OK;
@ -637,11 +643,14 @@ nsHTMLScrollFrame::ReflowContents(ScrollReflowState* aState,
// But don't try to show a scrollbar if we know there can't be one.
if (currentlyUsingVScrollbar || canHaveVerticalScrollbar) {
nsHTMLReflowMetrics kidRetrySize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags);
rv = ReflowScrolledFrame(*aState, !currentlyUsingVScrollbar,
rv = ReflowScrolledFrame(*aState, PR_FALSE, !currentlyUsingVScrollbar,
&kidRetrySize, PR_FALSE);
if (NS_FAILED(rv))
return rv;
didUseScrollbar = !currentlyUsingVScrollbar;
// XXX Adding a horizontal scrollbar could cause absolute children positioned
// relative to the bottom padding-edge to need to be reflowed. But we don't,
// because that would be slow.
if (TryLayout(aState, kidRetrySize, didUseScrollbar, PR_FALSE, PR_FALSE))
return NS_OK;
if (TryLayout(aState, kidRetrySize, didUseScrollbar, PR_TRUE, PR_FALSE))
@ -655,7 +664,7 @@ nsHTMLScrollFrame::ReflowContents(ScrollReflowState* aState,
// Fall back to no scrollbars --- even if NS_STYLE_OVERFLOW_SCROLL is
// in effect. They might not fit anyway.
if (didUseScrollbar) {
rv = ReflowScrolledFrame(*aState, PR_FALSE, &kidDesiredSize, PR_FALSE);
rv = ReflowScrolledFrame(*aState, PR_FALSE, PR_FALSE, &kidDesiredSize, PR_FALSE);
if (NS_FAILED(rv))
return rv;
}
@ -797,7 +806,7 @@ nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext,
// is deleted, because the XMost of the frame's overflow area is always
// at least the right edge. But it looks like it has always worked this way.
nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags);
rv = ReflowScrolledFrame(state, state.mShowVScrollbar,
rv = ReflowScrolledFrame(state, state.mShowHScrollbar, state.mShowVScrollbar,
&kidDesiredSize, PR_FALSE);
if (NS_FAILED(rv))
return rv;
@ -997,10 +1006,10 @@ nsMargin nsXULScrollFrame::GetDesiredScrollbarSizes(nsBoxLayoutState* aState) {
nsMargin nsGfxScrollFrameInner::GetDesiredScrollbarSizes(nsBoxLayoutState* aState) {
nsMargin result(0, 0, 0, 0);
if (mHScrollbarBox) {
if (mVScrollbarBox) {
nsSize size;
mHScrollbarBox->GetPrefSize(*aState, size);
nsBox::AddMargin(mHScrollbarBox, size);
mVScrollbarBox->GetPrefSize(*aState, size);
nsBox::AddMargin(mVScrollbarBox, size);
#ifdef IBMBIDI
if (IsScrollbarOnRight())
result.left = size.width;
@ -1009,10 +1018,10 @@ nsMargin nsGfxScrollFrameInner::GetDesiredScrollbarSizes(nsBoxLayoutState* aStat
result.right = size.width;
}
if (mVScrollbarBox) {
if (mHScrollbarBox) {
nsSize size;
mVScrollbarBox->GetPrefSize(*aState, size);
nsBox::AddMargin(mVScrollbarBox, size);
mHScrollbarBox->GetPrefSize(*aState, size);
nsBox::AddMargin(mHScrollbarBox, size);
// We don't currently support any scripts that would require a scrollbar
// at the top. (Are there any?)
result.bottom = size.height;

Просмотреть файл

@ -198,6 +198,7 @@ public:
PRBool aAssumeVScroll, PRBool aAssumeHScroll,
PRBool aForce);
nsresult ReflowScrolledFrame(const ScrollReflowState& aState,
PRBool aAssumeHScroll,
PRBool aAssumeVScroll,
nsHTMLReflowMetrics* aMetrics,
PRBool aFirstPass);

Просмотреть файл

@ -112,6 +112,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
mFlags.mSpecialHeightReflow = PR_FALSE;
mFlags.mIsTopOfPage = PR_FALSE;
mFlags.mNextInFlowUntouched = PR_FALSE;
mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = PR_FALSE;
mFlags.mHasClearance = PR_FALSE;
mDiscoveredClearance = nsnull;
mPercentHeightObserver = nsnull;
@ -146,6 +147,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
mFlags.mSpecialHeightReflow = PR_FALSE;
mFlags.mIsTopOfPage = PR_FALSE;
mFlags.mNextInFlowUntouched = PR_FALSE;
mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = PR_FALSE;
mFlags.mHasClearance = PR_FALSE;
mDiscoveredClearance = nsnull;
mPercentHeightObserver = nsnull;
@ -198,6 +200,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = PR_FALSE;
mFlags.mHasClearance = PR_FALSE;
mDiscoveredClearance = nsnull;
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
@ -247,6 +250,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = PR_FALSE;
mFlags.mHasClearance = PR_FALSE;
mDiscoveredClearance = nsnull;
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
@ -296,6 +300,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = PR_FALSE;
mFlags.mHasClearance = PR_FALSE;
mDiscoveredClearance = nsnull;
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&

Просмотреть файл

@ -265,6 +265,10 @@ struct nsHTMLReflowState {
PRUint16 mBlinks:1; // Keep track of text-decoration: blink
PRUint16 mVisualBidiFormControl:1; // Keep track of descendants of form controls on Visual Bidi pages
PRUint16 mHasClearance:1; // Block has clearance
PRUint16 mAssumingHScrollbar:1; // parent frame is an nsIScrollableFrame and it
// is assuming a horizontal scrollbar
PRUint16 mAssumingVScrollbar:1; // parent frame is an nsIScrollableFrame and it
// is assuming a vertical scrollbar
} mFlags;
#ifdef IBMBIDI

Просмотреть файл

@ -70,6 +70,8 @@ public:
/**
* Return the actual sizes of all possible scrollbars. Returns 0 for scrollbar
* positions that don't have a scrollbar or where the scrollbar is not visible.
* Do not call this while this frame's descendants are being reflowed, it won't be
* accurate.
*/
virtual nsMargin GetActualScrollbarSizes() const = 0;