Bug 508816 - layout patch

This commit is contained in:
Simon Montagu 2011-02-07 09:59:20 +02:00
parent 8847abc54d
commit e5ed17c7d6
2 changed files with 55 additions and 27 deletions

View File

@ -98,7 +98,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsHTMLScrollFrame)
nsHTMLScrollFrame::nsHTMLScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, PRBool aIsRoot)
: nsHTMLContainerFrame(aContext),
mInner(this, aIsRoot, PR_FALSE)
mInner(this, aIsRoot)
{
}
@ -978,7 +978,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsXULScrollFrame)
nsXULScrollFrame::nsXULScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, PRBool aIsRoot)
: nsBoxFrame(aShell, aContext, aIsRoot),
mInner(this, aIsRoot, PR_TRUE)
mInner(this, aIsRoot)
{
SetLayoutManager(nsnull);
}
@ -1351,8 +1351,7 @@ public:
static ScrollFrameActivityTracker *gScrollFrameActivityTracker = nsnull;
nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
PRBool aIsRoot,
PRBool aIsXUL)
PRBool aIsRoot)
: mHScrollbarBox(nsnull),
mVScrollbarBox(nsnull),
mScrolledFrame(nsnull),
@ -1371,7 +1370,6 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
mFrameIsUpdatingScrollbar(PR_FALSE),
mDidHistoryRestore(PR_FALSE),
mIsRoot(aIsRoot),
mIsXUL(aIsXUL),
mSupppressScrollbarUpdate(PR_FALSE),
mSkippedScrollbarLayout(PR_FALSE),
mHadNonInitialReflow(PR_FALSE),
@ -2101,18 +2099,21 @@ nsGfxScrollFrameInner::ScrollToRestoredPosition()
// make sure our scroll position did not change for where we last put
// it. if it does then the user must have moved it, and we no longer
// need to restore.
nsPoint scrollPos = GetScrollPosition();
//
// In the RTL case, we check whether the scroll position changed using the
// logical scroll position, but we scroll to the physical scroll position in
// all cases
// if we didn't move, we still need to restore
if (scrollPos == mLastPos) {
if (GetLogicalScrollPosition() == mLastPos) {
// if our desired position is different to the scroll position, scroll.
// remember that we could be incrementally loading so we may enter
// and scroll many times.
if (mRestorePos != scrollPos) {
if (mRestorePos != GetScrollPosition()) {
ScrollTo(mRestorePos, nsIScrollableFrame::INSTANT);
// Re-get the scroll position, it might not be exactly equal to
// mRestorePos due to rounding and clamping.
mLastPos = GetScrollPosition();
mLastPos = GetLogicalScrollPosition();
} else {
// if we reached the position then stop
mRestorePos.y = -1;
@ -2631,7 +2632,7 @@ nsXULScrollFrame::LayoutScrollArea(nsBoxLayoutState& aState,
const nsPoint& aScrollPosition)
{
PRUint32 oldflags = aState.LayoutFlags();
nsRect childRect = nsRect(mInner.mScrollPort.TopLeft() - aScrollPosition,
nsRect childRect = nsRect(nsPoint(0, 0),
mInner.mScrollPort.Size());
PRInt32 flags = NS_FRAME_NO_MOVE_VIEW;
@ -2664,6 +2665,26 @@ nsXULScrollFrame::LayoutScrollArea(nsBoxLayoutState& aState,
mInner.mScrolledFrame->SetBounds(aState, childRect, PR_TRUE);
}
/*
* After layout, restore the original position of the frame relative to the
* scroll port.
*
* In the LTR case, restore the original physical position (top left).
*
* In the RTL case, restore the original logical position (top right), then
* subtract the current width to find the physical position.
* This can break the invariant that the scroll position is a multiple of
* device pixels, so round off the result to the nearest device pixel.
*/
if (mInner.IsLTR())
childRect.x = mInner.mScrollPort.x - aScrollPosition.x;
else {
childRect.x = PresContext()->RoundAppUnitsToNearestDevPixels(
mInner.mScrollPort.XMost() - aScrollPosition.x - childRect.width);
}
childRect.y = mInner.mScrollPort.y - aScrollPosition.y;
mInner.mScrolledFrame->SetBounds(aState, childRect);
nsRect finalRect = mInner.mScrolledFrame->GetRect();
nsRect finalVisOverflow = mInner.mScrolledFrame->GetVisualOverflowRect();
// The position of the scrolled frame shouldn't change, but if it does or
@ -2784,7 +2805,7 @@ nsXULScrollFrame::Layout(nsBoxLayoutState& aState)
GetClientRect(clientRect);
nsRect oldScrollAreaBounds = mInner.mScrollPort;
nsPoint oldScrollPosition = mInner.GetScrollPosition();
nsPoint oldScrollPosition = mInner.GetLogicalScrollPosition();
// the scroll area size starts off as big as our content area
mInner.mScrollPort = clientRect;
@ -2838,10 +2859,9 @@ nsXULScrollFrame::Layout(nsBoxLayoutState& aState)
if (styles.mVertical != NS_STYLE_OVERFLOW_SCROLL) {
// These are only good until the call to LayoutScrollArea.
nsRect scrolledRect = mInner.GetScrolledRect();
nsSize scrolledContentSize(scrolledRect.XMost(), scrolledRect.YMost());
// There are two cases to consider
if (scrolledContentSize.height <= mInner.mScrollPort.height
if (scrolledRect.height <= mInner.mScrollPort.height
|| styles.mVertical != NS_STYLE_OVERFLOW_AUTO) {
if (mInner.mHasVerticalScrollbar) {
// We left room for the vertical scrollbar, but it's not needed;
@ -2872,11 +2892,10 @@ nsXULScrollFrame::Layout(nsBoxLayoutState& aState)
{
// These are only good until the call to LayoutScrollArea.
nsRect scrolledRect = mInner.GetScrolledRect();
nsSize scrolledContentSize(scrolledRect.XMost(), scrolledRect.YMost());
// if the child is wider that the scroll area
// and we don't have a scrollbar add one.
if (scrolledContentSize.width > mInner.mScrollPort.width
if ((scrolledRect.width > mInner.mScrollPort.width)
&& styles.mHorizontal == NS_STYLE_OVERFLOW_AUTO) {
if (!mInner.mHasHorizontalScrollbar) {
@ -2888,7 +2907,7 @@ nsXULScrollFrame::Layout(nsBoxLayoutState& aState)
// there is a chance that by adding the horizontal scrollbar we will
// suddenly need a vertical scrollbar. Is a special case but its
// important.
//if (!mHasVerticalScrollbar && scrolledContentSize.height > scrollAreaRect.height - sbSize.height)
//if (!mHasVerticalScrollbar && scrolledRect.height > scrollAreaRect.height - sbSize.height)
// printf("****Gfx Scrollbar Special case hit!!*****\n");
}
@ -3371,7 +3390,7 @@ nsGfxScrollFrameInner::GetScrolledRectInternal(const nsRect& aScrolledFrameOverf
y2 = aScrolledFrameOverflowArea.YMost();
if (y1 < 0)
y1 = 0;
if (IsLTR() || mIsXUL) {
if (IsLTR()) {
if (x1 < 0)
x1 = 0;
} else {
@ -3452,10 +3471,6 @@ nsGfxScrollFrameInner::SaveState(nsIStatefulFrame::SpecialStateID aStateID)
}
nsPoint scrollPos = GetScrollPosition();
// Don't save scroll position if we are at (0,0)
if (scrollPos == nsPoint(0,0)) {
return nsnull;
}
nsPresState* state = new nsPresState();
if (!state) {
@ -3474,7 +3489,7 @@ nsGfxScrollFrameInner::RestoreState(nsPresState* aState)
mLastPos.x = -1;
mLastPos.y = -1;
mDidHistoryRestore = PR_TRUE;
mLastPos = mScrolledFrame ? GetScrollPosition() : nsPoint(0,0);
mLastPos = mScrolledFrame ? GetLogicalScrollPosition() : nsPoint(0,0);
}
void

View File

@ -70,8 +70,7 @@ class nsGfxScrollFrameInner : public nsIReflowCallback {
public:
class AsyncScroll;
nsGfxScrollFrameInner(nsContainerFrame* aOuter, PRBool aIsRoot,
PRBool aIsXUL);
nsGfxScrollFrameInner(nsContainerFrame* aOuter, PRBool aIsRoot);
~nsGfxScrollFrameInner();
typedef nsIScrollableFrame::ScrollbarStyles ScrollbarStyles;
@ -154,6 +153,21 @@ public:
nsPoint GetScrollPosition() const {
return mScrollPort.TopLeft() - mScrolledFrame->GetPosition();
}
/**
* For LTR frames, the logical scroll position is the offset of the top left
* corner of the frame from the top left corner of the scroll port (same as
* GetScrollPosition).
* For RTL frames, it is the offset of the top right corner of the frame from
* the top right corner of the scroll port
*/
nsPoint GetLogicalScrollPosition() const {
nsPoint pt;
pt.x = IsLTR() ?
mScrollPort.x - mScrolledFrame->GetPosition().x :
mScrollPort.XMost() - mScrolledFrame->GetRect().XMost();
pt.y = mScrollPort.y - mScrolledFrame->GetPosition().y;
return pt;
}
nsRect GetScrollRange() const;
nsPoint ClampAndRestrictToDevPixels(const nsPoint& aPt, nsIntPoint* aPtDevPx) const;
@ -278,8 +292,6 @@ public:
PRPackedBool mDidHistoryRestore:1;
// Is this the scrollframe for the document's viewport?
PRPackedBool mIsRoot:1;
// Is mOuter an nsXULScrollFrame?
PRPackedBool mIsXUL:1;
// If true, don't try to layout the scrollbars in Reflow(). This can be
// useful if multiple passes are involved, because we don't want to place the
// scrollbars at the wrong size.
@ -600,7 +612,8 @@ public:
virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
{ nsPoint pt = aChild->GetPosition();
if (aChild == mInner.GetScrolledFrame()) pt += GetScrollPosition();
if (aChild == mInner.GetScrolledFrame())
pt += mInner.GetLogicalScrollPosition();
return pt;
}