зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
6729b6e9ae
Коммит
49188025d3
|
@ -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;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче