From b34a14698c874d45248df178ca95f161aa39f58c Mon Sep 17 00:00:00 2001 From: "troy%netscape.com" Date: Thu, 28 Jan 1999 17:14:13 +0000 Subject: [PATCH] More work-in-progress for fixed positioning git-svn-id: svn://10.0.0.236/trunk@18924 18797224-902f-48f8-a5cc-f745e15eee43 --- .../layout/generic/nsHTMLContainerFrame.cpp | 10 +- mozilla/layout/generic/nsHTMLReflowState.cpp | 2 +- mozilla/layout/generic/nsViewportFrame.cpp | 294 ++++++++++++++++-- .../html/base/src/nsHTMLContainerFrame.cpp | 10 +- .../html/base/src/nsHTMLReflowState.cpp | 2 +- .../layout/html/base/src/nsViewportFrame.cpp | 294 ++++++++++++++++-- 6 files changed, 558 insertions(+), 54 deletions(-) diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.cpp b/mozilla/layout/generic/nsHTMLContainerFrame.cpp index c080740ee06..24903e30d18 100644 --- a/mozilla/layout/generic/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/generic/nsHTMLContainerFrame.cpp @@ -41,8 +41,10 @@ #include "nsHTMLIIDs.h" #include "nsDOMEvent.h" #include "nsIScrollableView.h" +#include "nsWidgetsCID.h" static NS_DEFINE_IID(kScrollViewIID, NS_ISCROLLABLEVIEW_IID); +static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID); NS_IMETHODIMP nsHTMLContainerFrame::Paint(nsIPresContext& aPresContext, @@ -213,7 +215,7 @@ nsHTMLContainerFrame::CreateViewForFrame(nsIPresContext& aPresContext, aFrame)); aForce = PR_TRUE; - } else if (NS_STYLE_POSITION_ABSOLUTE == position->mPosition) { + } else if (position->IsAbsolutelyPositioned()) { NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("nsHTMLContainerFrame::CreateViewForFrame: frame=%p relatively positioned", aFrame)); @@ -326,6 +328,12 @@ nsHTMLContainerFrame::CreateViewForFrame(nsIPresContext& aPresContext, viewManager->SetViewContentTransparency(view, PR_TRUE); } + // XXX If it's fixed positioned, then create a widget so it floats + // above the scrolling area + if (NS_STYLE_POSITION_FIXED == position->mPosition) { + view->CreateWidget(kCChildCID); + } + viewManager->SetViewOpacity(view, color->mOpacity); NS_RELEASE(viewManager); } diff --git a/mozilla/layout/generic/nsHTMLReflowState.cpp b/mozilla/layout/generic/nsHTMLReflowState.cpp index ec21b5aa530..5eefaa23fbf 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.cpp +++ b/mozilla/layout/generic/nsHTMLReflowState.cpp @@ -110,7 +110,7 @@ nsHTMLReflowState::DetermineFrameType(nsIPresContext& aPresContext) frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); const nsStylePosition* pos; frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)pos); - if ((nsnull != pos) && (NS_STYLE_POSITION_ABSOLUTE == pos->mPosition)) { + if (pos->IsAbsolutelyPositioned()) { frameType = NS_CSS_FRAME_TYPE_ABSOLUTE; } else if (NS_STYLE_FLOAT_NONE != display->mFloats) { diff --git a/mozilla/layout/generic/nsViewportFrame.cpp b/mozilla/layout/generic/nsViewportFrame.cpp index 4e0b85af76d..1462efe4c74 100644 --- a/mozilla/layout/generic/nsViewportFrame.cpp +++ b/mozilla/layout/generic/nsViewportFrame.cpp @@ -15,9 +15,11 @@ * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ -#include "nsHTMLParts.h" #include "nsContainerFrame.h" +#include "nsHTMLParts.h" #include "nsHTMLIIDs.h" +#include "nsLayoutAtoms.h" +#include "nsIViewManager.h" static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); @@ -35,12 +37,39 @@ static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); */ class ViewportFrame : public nsContainerFrame { public: + NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext); + + NS_IMETHOD SetInitialChildList(nsIPresContext& aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList); + + NS_IMETHOD GetAdditionalChildListName(PRInt32 aIndex, + nsIAtom*& aListName) const; + + NS_IMETHOD FirstChild(nsIAtom* aListName, nsIFrame*& aFirstChild) const; + NS_IMETHOD Reflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); NS_IMETHOD GetFrameName(nsString& aResult) const; + +protected: + nsresult IncrementalReflow(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState); + + nsresult ReflowFixedFrame(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState, + nsIFrame* aKidFrame, + PRBool aInitialReflow, + nsReflowStatus& aStatus) const; + + void ReflowFixedFrames(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState) const; + +private: + nsFrameList mFixedFrames; // additional named child list }; //---------------------------------------------------------------------- @@ -56,6 +85,179 @@ NS_NewViewportFrame(nsIFrame*& aResult) return NS_OK; } +NS_IMETHODIMP +ViewportFrame::DeleteFrame(nsIPresContext& aPresContext) +{ + mFixedFrames.DeleteFrames(aPresContext); + return nsContainerFrame::DeleteFrame(aPresContext); +} + +NS_IMETHODIMP +ViewportFrame::SetInitialChildList(nsIPresContext& aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList) +{ + nsresult rv; + + if (nsLayoutAtoms::fixedList == aListName) { + mFixedFrames.SetFrames(aChildList); + rv = NS_OK; + } else { + rv = nsContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); + } + + return rv; +} + +NS_IMETHODIMP +ViewportFrame::GetAdditionalChildListName(PRInt32 aIndex, + nsIAtom*& aListName) const +{ + nsIAtom* atom = nsnull; + + if (aIndex < 0) { + return NS_ERROR_INVALID_ARG; + + } else if (0 == aIndex) { + atom = nsLayoutAtoms::fixedList; + NS_ADDREF(atom); + } + + aListName = atom; + return NS_OK; +} + +NS_IMETHODIMP +ViewportFrame::FirstChild(nsIAtom* aListName, nsIFrame*& aFirstChild) const +{ + if (aListName == nsLayoutAtoms::fixedList) { + aFirstChild = mFixedFrames.FirstChild(); + return NS_OK; + } + + return nsContainerFrame::FirstChild(aListName, aFirstChild); +} + +nsresult +ViewportFrame::ReflowFixedFrame(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState, + nsIFrame* aKidFrame, + PRBool aInitialReflow, + nsReflowStatus& aStatus) const +{ + // Reflow the frame + nsIHTMLReflow* htmlReflow; + nsresult rv; + + rv = aKidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); + if (NS_SUCCEEDED(rv)) { + htmlReflow->WillReflow(aPresContext); + + nsHTMLReflowMetrics kidDesiredSize(nsnull); + nsSize availSize(aReflowState.availableWidth, NS_UNCONSTRAINEDSIZE); + nsHTMLReflowState kidReflowState(aPresContext, aKidFrame, aReflowState, availSize); + + // If it's the initial reflow, then override the reflow reason. This is + // used when frames are inserted incrementally + if (aInitialReflow) { + kidReflowState.reason = eReflowReason_Initial; + } + + // XXX Temporary hack until the block/inline code starts using 'computedWidth' + kidReflowState.availableWidth = kidReflowState.computedWidth; + htmlReflow->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); + + // Position the child + nsRect rect(kidReflowState.computedOffsets.left, + kidReflowState.computedOffsets.top, + kidDesiredSize.width, kidDesiredSize.height); + aKidFrame->SetRect(rect); + htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + } + + return rv; +} + +// Called by Reflow() to reflow all of the fixed positioned child frames. +// This is only done for 'initial', 'resize', and 'style change' reflow commands +void +ViewportFrame::ReflowFixedFrames(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState) const +{ + NS_PRECONDITION(eReflowReason_Incremental != aReflowState.reason, + "unexpected reflow reason"); + + nsIFrame* kidFrame; + for (kidFrame = mFixedFrames.FirstChild(); nsnull != kidFrame; kidFrame->GetNextSibling(kidFrame)) { + // Reflow the frame using our reflow reason + nsReflowStatus kidStatus; + ReflowFixedFrame(aPresContext, aReflowState, kidFrame, PR_FALSE, + kidStatus); + } +} + +/** + * Called by Reflow() to handle the case where it's an incremental reflow + * of a fixed child frame + */ +nsresult +ViewportFrame::IncrementalReflow(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState) +{ + nsIReflowCommand::ReflowType type; + nsIFrame* newFrames; + PRInt32 numFrames; + + // Get the type of reflow command + aReflowState.reflowCommand->GetType(type); + + // Handle each specific type + if (nsIReflowCommand::FrameAppended == type) { + // Add the frames to our list of fixed position frames + aReflowState.reflowCommand->GetChildFrame(newFrames); + NS_ASSERTION(nsnull != newFrames, "null child list"); + numFrames = LengthOf(newFrames); + mFixedFrames.AppendFrames(nsnull, newFrames); + + } else if (nsIReflowCommand::FrameRemoved == type) { + // Get the new frame + nsIFrame* childFrame; + aReflowState.reflowCommand->GetChildFrame(childFrame); + + PRBool result = mFixedFrames.DeleteFrame(aPresContext, childFrame); + NS_ASSERTION(result, "didn't find frame to delete"); + + } else if (nsIReflowCommand::FrameInserted == type) { + // Get the previous sibling + nsIFrame* prevSibling; + aReflowState.reflowCommand->GetPrevSiblingFrame(prevSibling); + + // Insert the new frames + aReflowState.reflowCommand->GetChildFrame(newFrames); + NS_ASSERTION(nsnull != newFrames, "null child list"); + numFrames = LengthOf(newFrames); + mFixedFrames.InsertFrames(nsnull, prevSibling, newFrames); + + } else { + NS_ASSERTION(PR_FALSE, "unexpected reflow type"); + } + + // For inserted and appended reflow commands we need to reflow the + // newly added frames + if ((nsIReflowCommand::FrameAppended == type) || + (nsIReflowCommand::FrameInserted == type)) { + + while (numFrames-- > 0) { + nsReflowStatus status; + + ReflowFixedFrame(aPresContext, aReflowState, newFrames, PR_TRUE, status); + newFrames->GetNextSibling(newFrames); + } + } + + return NS_OK; +} + NS_IMETHODIMP ViewportFrame::Reflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -68,46 +270,88 @@ ViewportFrame::Reflow(nsIPresContext& aPresContext, // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; + nsIFrame* nextFrame = nsnull; + PRBool isHandled = PR_FALSE; + // Check for an incremental reflow if (eReflowReason_Incremental == aReflowState.reason) { // See if we're the target frame nsIFrame* targetFrame; aReflowState.reflowCommand->GetTarget(targetFrame); if (this == targetFrame) { - // The viewport does not support being the target of an incremental + nsIAtom* listName; + PRBool isFixedChild; + + // It's targeted at us. It better be for a 'fixed' frame // reflow command - NS_ASSERTION(PR_FALSE, "unexpected reflow command target"); + aReflowState.reflowCommand->GetChildListName(listName); + isFixedChild = nsLayoutAtoms::fixedList == listName; + NS_IF_RELEASE(listName); + NS_ASSERTION(isFixedChild, "unexpected child list"); + + if (isFixedChild) { + IncrementalReflow(aPresContext, aReflowState); + isHandled = PR_TRUE; + } } else { - nsIFrame* nextFrame; // Get the next frame in the reflow chain aReflowState.reflowCommand->GetNext(nextFrame); - NS_ASSERTION(nextFrame == mFrames.FirstChild(), "unexpected next reflow command frame"); } } - // Reflow our one and only child frame - if (mFrames.NotEmpty()) { - nsIFrame* kidFrame = mFrames.FirstChild(); - nsHTMLReflowMetrics desiredSize(nsnull); - nsSize availableSpace(aReflowState.availableWidth, - aReflowState.availableHeight); - nsHTMLReflowState kidReflowState(aPresContext, kidFrame, - aReflowState, availableSpace); + if (!isHandled) { + if ((eReflowReason_Incremental == aReflowState.reason) && + (mFixedFrames.ContainsFrame(nextFrame))) { + // Reflow the 'fixed' frame that's the next frame in the reflow path + nsReflowStatus kidStatus; + ReflowFixedFrame(aPresContext, aReflowState, nextFrame, PR_FALSE, + kidStatus); - // Reflow the frame - nsIHTMLReflow* htmlReflow; - if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { - kidReflowState.computedHeight = aReflowState.availableHeight; - ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, - aStatus); - - nsRect rect(0, 0, desiredSize.width, desiredSize.height); - kidFrame->SetRect(rect); + // XXX Make sure the frame is repainted. For the time being, since we + // have no idea what actually changed repaint it all... + nsIView* view; + nextFrame->GetView(view); + if (nsnull != view) { + nsIViewManager* viewMgr; + view->GetViewManager(viewMgr); + if (nsnull != viewMgr) { + viewMgr->UpdateView(view, (nsIRegion*)nsnull, NS_VMREFRESH_NO_SYNC); + NS_RELEASE(viewMgr); + } + } - // XXX We should resolve the details of who/when DidReflow() - // notifications are sent... - htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + } else { + // Reflow our one and only principal child frame + if (mFrames.NotEmpty()) { + nsIFrame* kidFrame = mFrames.FirstChild(); + nsHTMLReflowMetrics kidDesiredSize(nsnull); + nsSize availableSpace(aReflowState.availableWidth, + aReflowState.availableHeight); + nsHTMLReflowState kidReflowState(aPresContext, kidFrame, + aReflowState, availableSpace); + + // Reflow the frame + nsIHTMLReflow* htmlReflow; + if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { + kidReflowState.computedHeight = aReflowState.availableHeight; + ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, + aStatus); + + nsRect rect(0, 0, kidDesiredSize.width, kidDesiredSize.height); + kidFrame->SetRect(rect); + + // XXX We should resolve the details of who/when DidReflow() + // notifications are sent... + htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + } + } + + // If it's a 'initial', 'resize', or 'style change' reflow command (anything + // but incremental), then reflow all the fixed positioned child frames + if (eReflowReason_Incremental != aReflowState.reason) { + ReflowFixedFrames(aPresContext, aReflowState); + } } } diff --git a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp index c080740ee06..24903e30d18 100644 --- a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp @@ -41,8 +41,10 @@ #include "nsHTMLIIDs.h" #include "nsDOMEvent.h" #include "nsIScrollableView.h" +#include "nsWidgetsCID.h" static NS_DEFINE_IID(kScrollViewIID, NS_ISCROLLABLEVIEW_IID); +static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID); NS_IMETHODIMP nsHTMLContainerFrame::Paint(nsIPresContext& aPresContext, @@ -213,7 +215,7 @@ nsHTMLContainerFrame::CreateViewForFrame(nsIPresContext& aPresContext, aFrame)); aForce = PR_TRUE; - } else if (NS_STYLE_POSITION_ABSOLUTE == position->mPosition) { + } else if (position->IsAbsolutelyPositioned()) { NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("nsHTMLContainerFrame::CreateViewForFrame: frame=%p relatively positioned", aFrame)); @@ -326,6 +328,12 @@ nsHTMLContainerFrame::CreateViewForFrame(nsIPresContext& aPresContext, viewManager->SetViewContentTransparency(view, PR_TRUE); } + // XXX If it's fixed positioned, then create a widget so it floats + // above the scrolling area + if (NS_STYLE_POSITION_FIXED == position->mPosition) { + view->CreateWidget(kCChildCID); + } + viewManager->SetViewOpacity(view, color->mOpacity); NS_RELEASE(viewManager); } diff --git a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp index ec21b5aa530..5eefaa23fbf 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp +++ b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp @@ -110,7 +110,7 @@ nsHTMLReflowState::DetermineFrameType(nsIPresContext& aPresContext) frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); const nsStylePosition* pos; frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)pos); - if ((nsnull != pos) && (NS_STYLE_POSITION_ABSOLUTE == pos->mPosition)) { + if (pos->IsAbsolutelyPositioned()) { frameType = NS_CSS_FRAME_TYPE_ABSOLUTE; } else if (NS_STYLE_FLOAT_NONE != display->mFloats) { diff --git a/mozilla/layout/html/base/src/nsViewportFrame.cpp b/mozilla/layout/html/base/src/nsViewportFrame.cpp index 4e0b85af76d..1462efe4c74 100644 --- a/mozilla/layout/html/base/src/nsViewportFrame.cpp +++ b/mozilla/layout/html/base/src/nsViewportFrame.cpp @@ -15,9 +15,11 @@ * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ -#include "nsHTMLParts.h" #include "nsContainerFrame.h" +#include "nsHTMLParts.h" #include "nsHTMLIIDs.h" +#include "nsLayoutAtoms.h" +#include "nsIViewManager.h" static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); @@ -35,12 +37,39 @@ static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); */ class ViewportFrame : public nsContainerFrame { public: + NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext); + + NS_IMETHOD SetInitialChildList(nsIPresContext& aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList); + + NS_IMETHOD GetAdditionalChildListName(PRInt32 aIndex, + nsIAtom*& aListName) const; + + NS_IMETHOD FirstChild(nsIAtom* aListName, nsIFrame*& aFirstChild) const; + NS_IMETHOD Reflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); NS_IMETHOD GetFrameName(nsString& aResult) const; + +protected: + nsresult IncrementalReflow(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState); + + nsresult ReflowFixedFrame(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState, + nsIFrame* aKidFrame, + PRBool aInitialReflow, + nsReflowStatus& aStatus) const; + + void ReflowFixedFrames(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState) const; + +private: + nsFrameList mFixedFrames; // additional named child list }; //---------------------------------------------------------------------- @@ -56,6 +85,179 @@ NS_NewViewportFrame(nsIFrame*& aResult) return NS_OK; } +NS_IMETHODIMP +ViewportFrame::DeleteFrame(nsIPresContext& aPresContext) +{ + mFixedFrames.DeleteFrames(aPresContext); + return nsContainerFrame::DeleteFrame(aPresContext); +} + +NS_IMETHODIMP +ViewportFrame::SetInitialChildList(nsIPresContext& aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList) +{ + nsresult rv; + + if (nsLayoutAtoms::fixedList == aListName) { + mFixedFrames.SetFrames(aChildList); + rv = NS_OK; + } else { + rv = nsContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); + } + + return rv; +} + +NS_IMETHODIMP +ViewportFrame::GetAdditionalChildListName(PRInt32 aIndex, + nsIAtom*& aListName) const +{ + nsIAtom* atom = nsnull; + + if (aIndex < 0) { + return NS_ERROR_INVALID_ARG; + + } else if (0 == aIndex) { + atom = nsLayoutAtoms::fixedList; + NS_ADDREF(atom); + } + + aListName = atom; + return NS_OK; +} + +NS_IMETHODIMP +ViewportFrame::FirstChild(nsIAtom* aListName, nsIFrame*& aFirstChild) const +{ + if (aListName == nsLayoutAtoms::fixedList) { + aFirstChild = mFixedFrames.FirstChild(); + return NS_OK; + } + + return nsContainerFrame::FirstChild(aListName, aFirstChild); +} + +nsresult +ViewportFrame::ReflowFixedFrame(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState, + nsIFrame* aKidFrame, + PRBool aInitialReflow, + nsReflowStatus& aStatus) const +{ + // Reflow the frame + nsIHTMLReflow* htmlReflow; + nsresult rv; + + rv = aKidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); + if (NS_SUCCEEDED(rv)) { + htmlReflow->WillReflow(aPresContext); + + nsHTMLReflowMetrics kidDesiredSize(nsnull); + nsSize availSize(aReflowState.availableWidth, NS_UNCONSTRAINEDSIZE); + nsHTMLReflowState kidReflowState(aPresContext, aKidFrame, aReflowState, availSize); + + // If it's the initial reflow, then override the reflow reason. This is + // used when frames are inserted incrementally + if (aInitialReflow) { + kidReflowState.reason = eReflowReason_Initial; + } + + // XXX Temporary hack until the block/inline code starts using 'computedWidth' + kidReflowState.availableWidth = kidReflowState.computedWidth; + htmlReflow->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); + + // Position the child + nsRect rect(kidReflowState.computedOffsets.left, + kidReflowState.computedOffsets.top, + kidDesiredSize.width, kidDesiredSize.height); + aKidFrame->SetRect(rect); + htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + } + + return rv; +} + +// Called by Reflow() to reflow all of the fixed positioned child frames. +// This is only done for 'initial', 'resize', and 'style change' reflow commands +void +ViewportFrame::ReflowFixedFrames(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState) const +{ + NS_PRECONDITION(eReflowReason_Incremental != aReflowState.reason, + "unexpected reflow reason"); + + nsIFrame* kidFrame; + for (kidFrame = mFixedFrames.FirstChild(); nsnull != kidFrame; kidFrame->GetNextSibling(kidFrame)) { + // Reflow the frame using our reflow reason + nsReflowStatus kidStatus; + ReflowFixedFrame(aPresContext, aReflowState, kidFrame, PR_FALSE, + kidStatus); + } +} + +/** + * Called by Reflow() to handle the case where it's an incremental reflow + * of a fixed child frame + */ +nsresult +ViewportFrame::IncrementalReflow(nsIPresContext& aPresContext, + const nsHTMLReflowState& aReflowState) +{ + nsIReflowCommand::ReflowType type; + nsIFrame* newFrames; + PRInt32 numFrames; + + // Get the type of reflow command + aReflowState.reflowCommand->GetType(type); + + // Handle each specific type + if (nsIReflowCommand::FrameAppended == type) { + // Add the frames to our list of fixed position frames + aReflowState.reflowCommand->GetChildFrame(newFrames); + NS_ASSERTION(nsnull != newFrames, "null child list"); + numFrames = LengthOf(newFrames); + mFixedFrames.AppendFrames(nsnull, newFrames); + + } else if (nsIReflowCommand::FrameRemoved == type) { + // Get the new frame + nsIFrame* childFrame; + aReflowState.reflowCommand->GetChildFrame(childFrame); + + PRBool result = mFixedFrames.DeleteFrame(aPresContext, childFrame); + NS_ASSERTION(result, "didn't find frame to delete"); + + } else if (nsIReflowCommand::FrameInserted == type) { + // Get the previous sibling + nsIFrame* prevSibling; + aReflowState.reflowCommand->GetPrevSiblingFrame(prevSibling); + + // Insert the new frames + aReflowState.reflowCommand->GetChildFrame(newFrames); + NS_ASSERTION(nsnull != newFrames, "null child list"); + numFrames = LengthOf(newFrames); + mFixedFrames.InsertFrames(nsnull, prevSibling, newFrames); + + } else { + NS_ASSERTION(PR_FALSE, "unexpected reflow type"); + } + + // For inserted and appended reflow commands we need to reflow the + // newly added frames + if ((nsIReflowCommand::FrameAppended == type) || + (nsIReflowCommand::FrameInserted == type)) { + + while (numFrames-- > 0) { + nsReflowStatus status; + + ReflowFixedFrame(aPresContext, aReflowState, newFrames, PR_TRUE, status); + newFrames->GetNextSibling(newFrames); + } + } + + return NS_OK; +} + NS_IMETHODIMP ViewportFrame::Reflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -68,46 +270,88 @@ ViewportFrame::Reflow(nsIPresContext& aPresContext, // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; + nsIFrame* nextFrame = nsnull; + PRBool isHandled = PR_FALSE; + // Check for an incremental reflow if (eReflowReason_Incremental == aReflowState.reason) { // See if we're the target frame nsIFrame* targetFrame; aReflowState.reflowCommand->GetTarget(targetFrame); if (this == targetFrame) { - // The viewport does not support being the target of an incremental + nsIAtom* listName; + PRBool isFixedChild; + + // It's targeted at us. It better be for a 'fixed' frame // reflow command - NS_ASSERTION(PR_FALSE, "unexpected reflow command target"); + aReflowState.reflowCommand->GetChildListName(listName); + isFixedChild = nsLayoutAtoms::fixedList == listName; + NS_IF_RELEASE(listName); + NS_ASSERTION(isFixedChild, "unexpected child list"); + + if (isFixedChild) { + IncrementalReflow(aPresContext, aReflowState); + isHandled = PR_TRUE; + } } else { - nsIFrame* nextFrame; // Get the next frame in the reflow chain aReflowState.reflowCommand->GetNext(nextFrame); - NS_ASSERTION(nextFrame == mFrames.FirstChild(), "unexpected next reflow command frame"); } } - // Reflow our one and only child frame - if (mFrames.NotEmpty()) { - nsIFrame* kidFrame = mFrames.FirstChild(); - nsHTMLReflowMetrics desiredSize(nsnull); - nsSize availableSpace(aReflowState.availableWidth, - aReflowState.availableHeight); - nsHTMLReflowState kidReflowState(aPresContext, kidFrame, - aReflowState, availableSpace); + if (!isHandled) { + if ((eReflowReason_Incremental == aReflowState.reason) && + (mFixedFrames.ContainsFrame(nextFrame))) { + // Reflow the 'fixed' frame that's the next frame in the reflow path + nsReflowStatus kidStatus; + ReflowFixedFrame(aPresContext, aReflowState, nextFrame, PR_FALSE, + kidStatus); - // Reflow the frame - nsIHTMLReflow* htmlReflow; - if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { - kidReflowState.computedHeight = aReflowState.availableHeight; - ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, - aStatus); - - nsRect rect(0, 0, desiredSize.width, desiredSize.height); - kidFrame->SetRect(rect); + // XXX Make sure the frame is repainted. For the time being, since we + // have no idea what actually changed repaint it all... + nsIView* view; + nextFrame->GetView(view); + if (nsnull != view) { + nsIViewManager* viewMgr; + view->GetViewManager(viewMgr); + if (nsnull != viewMgr) { + viewMgr->UpdateView(view, (nsIRegion*)nsnull, NS_VMREFRESH_NO_SYNC); + NS_RELEASE(viewMgr); + } + } - // XXX We should resolve the details of who/when DidReflow() - // notifications are sent... - htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + } else { + // Reflow our one and only principal child frame + if (mFrames.NotEmpty()) { + nsIFrame* kidFrame = mFrames.FirstChild(); + nsHTMLReflowMetrics kidDesiredSize(nsnull); + nsSize availableSpace(aReflowState.availableWidth, + aReflowState.availableHeight); + nsHTMLReflowState kidReflowState(aPresContext, kidFrame, + aReflowState, availableSpace); + + // Reflow the frame + nsIHTMLReflow* htmlReflow; + if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { + kidReflowState.computedHeight = aReflowState.availableHeight; + ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, + aStatus); + + nsRect rect(0, 0, kidDesiredSize.width, kidDesiredSize.height); + kidFrame->SetRect(rect); + + // XXX We should resolve the details of who/when DidReflow() + // notifications are sent... + htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + } + } + + // If it's a 'initial', 'resize', or 'style change' reflow command (anything + // but incremental), then reflow all the fixed positioned child frames + if (eReflowReason_Incremental != aReflowState.reason) { + ReflowFixedFrames(aPresContext, aReflowState); + } } }