From b90fd2dc6480e04ea0083e905e8ce44fbf8bc82d Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Tue, 17 Apr 2001 01:45:38 +0000 Subject: [PATCH] Fix calculation of scrollbar widths for laying out fixed-position frames. Also make sure that the fixed frames are reflowed if scrollbar widths change. Fix for bug 5195. r=evaughan,sr=attinasi --- layout/generic/nsGfxScrollFrame.cpp | 34 +++++++++++++-- layout/generic/nsViewportFrame.cpp | 52 ++++++++++------------- layout/html/base/src/nsGfxScrollFrame.cpp | 34 +++++++++++++-- layout/html/base/src/nsScrollFrame.cpp | 33 ++++++++++++++ layout/html/base/src/nsViewportFrame.cpp | 52 ++++++++++------------- 5 files changed, 141 insertions(+), 64 deletions(-) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 81263d605d6..407ff88687f 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1134,7 +1134,8 @@ nsGfxScrollFrameInner::Layout(nsBoxLayoutState& aState) if (mHasVerticalScrollbar) AddVerticalScrollbar(aState, scrollAreaRect, scrollBarRight); - + nsRect oldScrollAreaBounds; + mScrollAreaBox->GetClientRect(oldScrollAreaBounds); // layout our the scroll area LayoutBox(aState, mScrollAreaBox, scrollAreaRect); @@ -1347,10 +1348,37 @@ nsGfxScrollFrameInner::Layout(nsBoxLayoutState& aState) needsLayout = PR_FALSE; } - + // may need to update fixed position children of the viewport, + // if the client area changed size because of some dirty reflow + // (if the reflow is initial or resize, the fixed children will + // be re-laid out anyway) + if ((oldScrollAreaBounds.width != scrollAreaRect.width + || oldScrollAreaBounds.height != scrollAreaRect.height) + && nsBoxLayoutState::Dirty == aState.GetLayoutReason()) { + nsIFrame* parentFrame; + mOuter->GetParent(&parentFrame); + if (parentFrame) { + nsCOMPtr parentFrameType; + parentFrame->GetFrameType(getter_AddRefs(parentFrameType)); + if (parentFrameType.get() == nsLayoutAtoms::viewportFrame) { + // Usually there are no fixed children, so don't do anything unless there's + // at least one fixed child + nsIFrame* child; + if (NS_SUCCEEDED(parentFrame->FirstChild(mOuter->mPresContext, + nsLayoutAtoms::fixedList, &child)) && child) { + nsCOMPtr presShell; + mOuter->mPresContext->GetShell(getter_AddRefs(presShell)); + + // force a reflow of the fixed children + nsFrame::CreateAndPostReflowCommand(presShell, parentFrame, + nsIReflowCommand::UserDefined, nsnull, nsnull, nsLayoutAtoms::fixedList); + } + } + } + } return NS_OK; -} +} void nsGfxScrollFrameInner::ScrollbarChanged(nsIPresContext* aPresContext, nscoord aX, nscoord aY) diff --git a/layout/generic/nsViewportFrame.cpp b/layout/generic/nsViewportFrame.cpp index 81bfa0e0eb5..2851a47d95d 100644 --- a/layout/generic/nsViewportFrame.cpp +++ b/layout/generic/nsViewportFrame.cpp @@ -25,7 +25,7 @@ #include "nsHTMLIIDs.h" #include "nsLayoutAtoms.h" #include "nsIViewManager.h" -#include "nsIScrollableView.h" +#include "nsIScrollableFrame.h" #include "nsIDeviceContext.h" #include "nsIPresContext.h" #include "nsIReflowCommand.h" @@ -310,30 +310,18 @@ ViewportFrame::CalculateFixedContainingBlockSize(nsIPresContext* aPresC // Get our prinicpal child frame and see if we're scrollable nsIFrame* kidFrame = mFrames.FirstChild(); - nsIView* kidView; + nsCOMPtr scrollingFrame(do_QueryInterface(kidFrame)); - kidFrame->GetView(aPresContext, &kidView); - if (nsnull != kidView) { - nsIScrollableView* scrollingView; - - if (NS_SUCCEEDED(kidView->QueryInterface(NS_GET_IID(nsIScrollableView), (void**)&scrollingView))) { - // Get the scrollbar dimensions - float sbWidth, sbHeight; - nsCOMPtr dc; - aPresContext->GetDeviceContext(getter_AddRefs(dc)); - - dc->GetScrollBarDimensions(sbWidth, sbHeight); - - // See if the scrollbars are visible - PRBool vertSBVisible, horzSBVisible; - - scrollingView->GetScrollbarVisibility(&vertSBVisible, &horzSBVisible); - if (vertSBVisible) { - aWidth -= NSToCoordRound(sbWidth); - } - if (horzSBVisible) { - aHeight -= NSToCoordRound(sbHeight); - } + if (scrollingFrame) { + nscoord sbWidth = 0, sbHeight = 0; + PRBool sbHVisible = PR_FALSE, sbVVisible = PR_FALSE; + scrollingFrame->GetScrollbarSizes(aPresContext, &sbWidth, &sbHeight); + scrollingFrame->GetScrollbarVisibility(aPresContext, &sbVVisible, &sbHVisible); + if (sbVVisible) { + aWidth -= sbWidth; + } + if (sbHVisible) { + aHeight -= sbHeight; } } } @@ -402,9 +390,6 @@ void ViewportFrame::ReflowFixedFrames(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState) const { - NS_PRECONDITION(eReflowReason_Incremental != aReflowState.reason, - "unexpected reflow reason"); - // Calculate how much room is available for the fixed items. That means // determining if the viewport is scrollable and whether the vertical and/or // horizontal scrollbars are visible @@ -490,8 +475,17 @@ ViewportFrame::Reflow(nsIPresContext* aPresContext, nsIFrame* nextFrame = nsnull; PRBool isHandled = PR_FALSE; - // Check for an incremental reflow - if (eReflowReason_Incremental == aReflowState.reason) { + nsIReflowCommand::ReflowType reflowType = nsIReflowCommand::ContentChanged; + if (aReflowState.reflowCommand) { + aReflowState.reflowCommand->GetType(reflowType); + } + if (reflowType == nsIReflowCommand::UserDefined) { + // Reflow the fixed frames to account for changed scrolled area size + ReflowFixedFrames(aPresContext, aReflowState); + isHandled = PR_TRUE; + + // Otherwise check for an incremental reflow + } else if (eReflowReason_Incremental == aReflowState.reason) { // See if we're the target frame nsIFrame* targetFrame; aReflowState.reflowCommand->GetTarget(targetFrame); diff --git a/layout/html/base/src/nsGfxScrollFrame.cpp b/layout/html/base/src/nsGfxScrollFrame.cpp index 81263d605d6..407ff88687f 100644 --- a/layout/html/base/src/nsGfxScrollFrame.cpp +++ b/layout/html/base/src/nsGfxScrollFrame.cpp @@ -1134,7 +1134,8 @@ nsGfxScrollFrameInner::Layout(nsBoxLayoutState& aState) if (mHasVerticalScrollbar) AddVerticalScrollbar(aState, scrollAreaRect, scrollBarRight); - + nsRect oldScrollAreaBounds; + mScrollAreaBox->GetClientRect(oldScrollAreaBounds); // layout our the scroll area LayoutBox(aState, mScrollAreaBox, scrollAreaRect); @@ -1347,10 +1348,37 @@ nsGfxScrollFrameInner::Layout(nsBoxLayoutState& aState) needsLayout = PR_FALSE; } - + // may need to update fixed position children of the viewport, + // if the client area changed size because of some dirty reflow + // (if the reflow is initial or resize, the fixed children will + // be re-laid out anyway) + if ((oldScrollAreaBounds.width != scrollAreaRect.width + || oldScrollAreaBounds.height != scrollAreaRect.height) + && nsBoxLayoutState::Dirty == aState.GetLayoutReason()) { + nsIFrame* parentFrame; + mOuter->GetParent(&parentFrame); + if (parentFrame) { + nsCOMPtr parentFrameType; + parentFrame->GetFrameType(getter_AddRefs(parentFrameType)); + if (parentFrameType.get() == nsLayoutAtoms::viewportFrame) { + // Usually there are no fixed children, so don't do anything unless there's + // at least one fixed child + nsIFrame* child; + if (NS_SUCCEEDED(parentFrame->FirstChild(mOuter->mPresContext, + nsLayoutAtoms::fixedList, &child)) && child) { + nsCOMPtr presShell; + mOuter->mPresContext->GetShell(getter_AddRefs(presShell)); + + // force a reflow of the fixed children + nsFrame::CreateAndPostReflowCommand(presShell, parentFrame, + nsIReflowCommand::UserDefined, nsnull, nsnull, nsLayoutAtoms::fixedList); + } + } + } + } return NS_OK; -} +} void nsGfxScrollFrameInner::ScrollbarChanged(nsIPresContext* aPresContext, nscoord aX, nscoord aY) diff --git a/layout/html/base/src/nsScrollFrame.cpp b/layout/html/base/src/nsScrollFrame.cpp index f357b2e5119..f555f73cdab 100644 --- a/layout/html/base/src/nsScrollFrame.cpp +++ b/layout/html/base/src/nsScrollFrame.cpp @@ -646,6 +646,9 @@ nsScrollFrame::Reflow(nsIPresContext* aPresContext, nsIFrame* targetFrame; nsIFrame* nextFrame; + nsRect oldKidBounds; + kidFrame->GetRect(oldKidBounds); + // Special handling for incremental reflow if (eReflowReason_Incremental == aReflowState.reason) { // See whether we're the target of the reflow command @@ -858,6 +861,36 @@ nsScrollFrame::Reflow(nsIPresContext* aPresContext, CalculateChildTotalSize(kidFrame, kidDesiredSize); } } + + nsRect newKidBounds; + kidFrame->GetRect(newKidBounds); + + // may need to update fixed position children of the viewport, + // if the client area changed size + if ((oldKidBounds.width != newKidBounds.width + || oldKidBounds.height != newKidBounds.height) + && eReflowReason_Incremental == aReflowState.reason) { + nsIFrame* parentFrame; + GetParent(&parentFrame); + if (parentFrame) { + nsCOMPtr parentFrameType; + parentFrame->GetFrameType(getter_AddRefs(parentFrameType)); + if (parentFrameType.get() == nsLayoutAtoms::viewportFrame) { + // Usually there are no fixed children, so don't do anything unless there's + // at least one fixed child + nsIFrame* child; + if (NS_SUCCEEDED(parentFrame->FirstChild(aPresContext, + nsLayoutAtoms::fixedList, &child)) && child) { + nsCOMPtr presShell; + aPresContext->GetShell(getter_AddRefs(presShell)); + + // force a reflow of the fixed children + nsFrame::CreateAndPostReflowCommand(presShell, parentFrame, + nsIReflowCommand::UserDefined, nsnull, nsnull, nsLayoutAtoms::fixedList); + } + } + } + } if (aReflowState.mStyleDisplay->mOverflow != NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL) { diff --git a/layout/html/base/src/nsViewportFrame.cpp b/layout/html/base/src/nsViewportFrame.cpp index 81bfa0e0eb5..2851a47d95d 100644 --- a/layout/html/base/src/nsViewportFrame.cpp +++ b/layout/html/base/src/nsViewportFrame.cpp @@ -25,7 +25,7 @@ #include "nsHTMLIIDs.h" #include "nsLayoutAtoms.h" #include "nsIViewManager.h" -#include "nsIScrollableView.h" +#include "nsIScrollableFrame.h" #include "nsIDeviceContext.h" #include "nsIPresContext.h" #include "nsIReflowCommand.h" @@ -310,30 +310,18 @@ ViewportFrame::CalculateFixedContainingBlockSize(nsIPresContext* aPresC // Get our prinicpal child frame and see if we're scrollable nsIFrame* kidFrame = mFrames.FirstChild(); - nsIView* kidView; + nsCOMPtr scrollingFrame(do_QueryInterface(kidFrame)); - kidFrame->GetView(aPresContext, &kidView); - if (nsnull != kidView) { - nsIScrollableView* scrollingView; - - if (NS_SUCCEEDED(kidView->QueryInterface(NS_GET_IID(nsIScrollableView), (void**)&scrollingView))) { - // Get the scrollbar dimensions - float sbWidth, sbHeight; - nsCOMPtr dc; - aPresContext->GetDeviceContext(getter_AddRefs(dc)); - - dc->GetScrollBarDimensions(sbWidth, sbHeight); - - // See if the scrollbars are visible - PRBool vertSBVisible, horzSBVisible; - - scrollingView->GetScrollbarVisibility(&vertSBVisible, &horzSBVisible); - if (vertSBVisible) { - aWidth -= NSToCoordRound(sbWidth); - } - if (horzSBVisible) { - aHeight -= NSToCoordRound(sbHeight); - } + if (scrollingFrame) { + nscoord sbWidth = 0, sbHeight = 0; + PRBool sbHVisible = PR_FALSE, sbVVisible = PR_FALSE; + scrollingFrame->GetScrollbarSizes(aPresContext, &sbWidth, &sbHeight); + scrollingFrame->GetScrollbarVisibility(aPresContext, &sbVVisible, &sbHVisible); + if (sbVVisible) { + aWidth -= sbWidth; + } + if (sbHVisible) { + aHeight -= sbHeight; } } } @@ -402,9 +390,6 @@ void ViewportFrame::ReflowFixedFrames(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState) const { - NS_PRECONDITION(eReflowReason_Incremental != aReflowState.reason, - "unexpected reflow reason"); - // Calculate how much room is available for the fixed items. That means // determining if the viewport is scrollable and whether the vertical and/or // horizontal scrollbars are visible @@ -490,8 +475,17 @@ ViewportFrame::Reflow(nsIPresContext* aPresContext, nsIFrame* nextFrame = nsnull; PRBool isHandled = PR_FALSE; - // Check for an incremental reflow - if (eReflowReason_Incremental == aReflowState.reason) { + nsIReflowCommand::ReflowType reflowType = nsIReflowCommand::ContentChanged; + if (aReflowState.reflowCommand) { + aReflowState.reflowCommand->GetType(reflowType); + } + if (reflowType == nsIReflowCommand::UserDefined) { + // Reflow the fixed frames to account for changed scrolled area size + ReflowFixedFrames(aPresContext, aReflowState); + isHandled = PR_TRUE; + + // Otherwise check for an incremental reflow + } else if (eReflowReason_Incremental == aReflowState.reason) { // See if we're the target frame nsIFrame* targetFrame; aReflowState.reflowCommand->GetTarget(targetFrame);