Bug 32770: Save scroll position in session history r=nisheeth

git-svn-id: svn://10.0.0.236/trunk@72258 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
pollmann%netscape.com 2000-06-15 00:35:46 +00:00
parent bcefbad6b8
commit d5ebd0e9c7
14 changed files with 559 additions and 93 deletions

View File

@ -3128,7 +3128,7 @@ NS_IMETHODIMP nsDocShell::UpdateCurrentSessionHistory()
if (NS_SUCCEEDED(rv) && shell) {
nsCOMPtr<nsILayoutHistoryState> layoutState;
rv = shell->CaptureHistoryState(getter_AddRefs(layoutState));
rv = shell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE);
if (NS_SUCCEEDED(rv) && layoutState) {
rv = entry->SetLayoutHistoryState(layoutState);

View File

@ -248,12 +248,22 @@ public:
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
// Capture state from the entire frame heirarchy and store in aState
NS_IMETHOD CaptureFrameState(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState);
NS_IMETHOD RestoreFrameState(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState);
// Add/restore state for one frame (special, global type, like scroll position)
NS_IMETHOD CaptureFrameStateFor(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState,
nsIStatefulFrame::SpecialStateID aID = nsIStatefulFrame::eNoID);
NS_IMETHOD RestoreFrameStateFor(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState,
nsIStatefulFrame::SpecialStateID aID = nsIStatefulFrame::eNoID);
// Gets and sets properties on a given frame
NS_IMETHOD GetFrameProperty(nsIFrame* aFrame,
@ -1477,8 +1487,10 @@ FrameManager::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
return rv;
}
static nsresult
CaptureFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState)
// Capture state for a given frame.
// Accept a content id here, in some cases we may not have content (scroll position)
NS_IMETHODIMP
FrameManager::CaptureFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState, nsIStatefulFrame::SpecialStateID aID)
{
nsresult rv = NS_OK;
NS_PRECONDITION(nsnull != aFrame && nsnull != aState, "null parameters passed in");
@ -1488,23 +1500,31 @@ CaptureFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHi
nsIStatefulFrame* statefulFrame = nsnull;
aFrame->QueryInterface(NS_GET_IID(nsIStatefulFrame), (void**) &statefulFrame);
if (nsnull != statefulFrame) {
// If so, get the content ID, state type and the state and
// add an association between (ID, type) and (state) to the
// history state storage object, aState.
nsCOMPtr<nsIContent> content;
rv = aFrame->GetContent(getter_AddRefs(content));
if (NS_SUCCEEDED(rv)) {
PRUint32 ID;
rv = content->GetContentID(&ID);
if (NS_SUCCEEDED(rv) && ID) { // Must have ID (don't do anonymous content)
nsIStatefulFrame::StateType type = nsIStatefulFrame::eNoType;
rv = statefulFrame->GetStateType(aPresContext, &type);
// If not given one, get the content ID
PRUint32 ID = aID;
if (nsIStatefulFrame::eNoID == ID) {
nsCOMPtr<nsIContent> content;
rv = aFrame->GetContent(getter_AddRefs(content));
if (NS_SUCCEEDED(rv) && content) {
rv = content->GetContentID(&ID);
}
}
if (NS_SUCCEEDED(rv) && ID) { // Must have ID (don't do anonymous content)
// Get the state type
nsIStatefulFrame::StateType type = nsIStatefulFrame::eNoType;
rv = statefulFrame->GetStateType(aPresContext, &type);
if (NS_SUCCEEDED(rv)) {
// Get the state
nsCOMPtr<nsIPresState> frameState;
rv = statefulFrame->SaveState(aPresContext, getter_AddRefs(frameState));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPresState> frameState;
rv = statefulFrame->SaveState(aPresContext, getter_AddRefs(frameState));
if (NS_SUCCEEDED(rv)) {
rv = aState->AddState(ID, frameState, type);
}
// add an association between (ID, type) and (state) to the
// history state storage object, aState.
rv = aState->AddState(ID, frameState, type);
}
}
}
@ -1539,8 +1559,10 @@ FrameManager::CaptureFrameState(nsIPresContext* aPresContext, nsIFrame* aFrame,
return rv;
}
static nsresult
RestoreFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState)
// Restore state for a given frame.
// Accept a content id here, in some cases we may not have content (scroll position)
NS_IMETHODIMP
FrameManager::RestoreFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState, nsIStatefulFrame::SpecialStateID aID)
{
nsresult rv = NS_OK;
NS_PRECONDITION(nsnull != aFrame && nsnull != aState, "null parameters passed in");
@ -1550,26 +1572,30 @@ RestoreFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHi
nsIStatefulFrame* statefulFrame = nsnull;
aFrame->QueryInterface(NS_GET_IID(nsIStatefulFrame), (void**) &statefulFrame);
if (nsnull != statefulFrame) {
// If so, get the content ID, state type and the frame state and
// ask the frame object to restore its state.
nsCOMPtr<nsIContent> content;
rv = aFrame->GetContent(getter_AddRefs(content));
if (NS_SUCCEEDED(rv)) {
PRUint32 ID;
rv = content->GetContentID(&ID);
if (NS_SUCCEEDED(rv) && ID) { // Must have ID (don't do anonymous content)
nsIStatefulFrame::StateType type = nsIStatefulFrame::eNoType;
rv = statefulFrame->GetStateType(aPresContext, &type);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPresState> frameState;
rv = aState->GetState(ID, getter_AddRefs(frameState), type);
if (NS_SUCCEEDED(rv) && frameState) {
// First restore the state.
rv = statefulFrame->RestoreState(aPresContext, frameState);
// Now remove the state from the state table.
aState->RemoveState(ID, type);
}
// If not given one, get the content ID
PRUint32 ID = aID;
if (nsIStatefulFrame::eNoID == ID) {
nsCOMPtr<nsIContent> content;
rv = aFrame->GetContent(getter_AddRefs(content));
if (NS_SUCCEEDED(rv) && content) {
rv = content->GetContentID(&ID);
}
}
if (NS_SUCCEEDED(rv) && ID) { // Must have ID (don't do anonymous content)
nsIStatefulFrame::StateType type = nsIStatefulFrame::eNoType;
rv = statefulFrame->GetStateType(aPresContext, &type);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPresState> frameState;
rv = aState->GetState(ID, getter_AddRefs(frameState), type);
if (NS_SUCCEEDED(rv) && frameState) {
// First restore the state.
rv = statefulFrame->RestoreState(aPresContext, frameState);
// Now remove the state from the state table.
aState->RemoveState(ID, type);
}
}
}

View File

@ -369,7 +369,7 @@ public:
* Get and set the history state for the current document
*/
NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState) = 0;
NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage = PR_FALSE) = 0;
NS_IMETHOD GetHistoryState(nsILayoutHistoryState** aLayoutHistoryState) = 0;
NS_IMETHOD SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState) = 0;

View File

@ -642,7 +642,7 @@ public:
NS_IMETHOD DoCopy();
NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState);
NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage);
NS_IMETHOD GetHistoryState(nsILayoutHistoryState** aLayoutHistoryState);
NS_IMETHOD SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState);
@ -1543,6 +1543,45 @@ PresShell::NotifyReflowObservers(const char *aData)
return NS_OK;
}
static nsresult
GetRootScrollFrame(nsIPresContext* aPresContext, nsIFrame* aRootFrame, nsIFrame** aScrollFrame) {
// Frames: viewport->scroll->scrollport (Gfx) or viewport->scroll (Native)
// Types: viewport->scroll->sroll viewport->scroll
// Ensure root frame is a viewport frame
*aScrollFrame = nsnull;
nsIFrame* theFrame = nsnull;
if (aRootFrame) {
nsCOMPtr<nsIAtom> fType;
aRootFrame->GetFrameType(getter_AddRefs(fType));
if (fType && (nsLayoutAtoms::viewportFrame == fType.get())) {
// If child is scrollframe keep it (native)
aRootFrame->FirstChild(aPresContext, nsnull, &theFrame);
if (theFrame) {
nsCOMPtr<nsIAtom> fType;
theFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::scrollFrame == fType.get()) {
*aScrollFrame = theFrame;
// If the first child of that is scrollframe, use it instead (gfx)
theFrame->FirstChild(aPresContext, nsnull, &theFrame);
if (theFrame) {
nsCOMPtr<nsIAtom> fType;
theFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::scrollFrame == fType.get()) {
*aScrollFrame = theFrame;
}
}
}
}
}
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
{
@ -2237,6 +2276,18 @@ PresShell::BeginLoad(nsIDocument *aDocument)
NS_IMETHODIMP
PresShell::EndLoad(nsIDocument *aDocument)
{
// Restore frame state for the root scroll frame
nsIFrame* rootFrame = nsnull;
GetRootFrame(&rootFrame);
if (rootFrame && mHistoryState) {
nsIFrame* scrollFrame = nsnull;
GetRootScrollFrame(mPresContext, rootFrame, &scrollFrame);
if (scrollFrame) {
mFrameManager->RestoreFrameStateFor(mPresContext, scrollFrame, mHistoryState, nsIStatefulFrame::eDocumentScrollState);
}
}
#ifdef MOZ_PERF_METRICS
// Dump reflow, style resolution and frame construction times here.
MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::EndLoad(), this=%p\n", this));
@ -2814,7 +2865,7 @@ PresShell::DoCopy()
}
NS_IMETHODIMP
PresShell::CaptureHistoryState(nsILayoutHistoryState** aState)
PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPage)
{
nsresult rv = NS_OK;
@ -2840,6 +2891,18 @@ PresShell::CaptureHistoryState(nsILayoutHistoryState** aState)
nsIFrame* rootFrame = nsnull;
rv = GetRootFrame(&rootFrame);
if (NS_FAILED(rv) || nsnull == rootFrame) return rv;
// Capture frame state for the root scroll frame
// Don't capture state when first creating doc element heirarchy
// As the scroll position is 0 and this will cause us to loose
// our previously saved place!
if (aLeavingPage) {
nsIFrame* scrollFrame = nsnull;
rv = GetRootScrollFrame(mPresContext, rootFrame, &scrollFrame);
if (scrollFrame) {
rv = mFrameManager->CaptureFrameStateFor(mPresContext, scrollFrame, mHistoryState, nsIStatefulFrame::eDocumentScrollState);
}
}
rv = mFrameManager->CaptureFrameState(mPresContext, rootFrame, mHistoryState);

View File

@ -24,6 +24,7 @@
#include "nslayout.h"
#include "nsISupports.h"
#include "nsIStatefulFrame.h"
class nsIAtom;
class nsIContent;
@ -165,6 +166,15 @@ public:
NS_IMETHOD RestoreFrameState(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState) = 0;
// Add/restore state for one frame (special, global type, like scroll position)
NS_IMETHOD CaptureFrameStateFor(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState,
nsIStatefulFrame::SpecialStateID aID = nsIStatefulFrame::eNoID) = 0;
NS_IMETHOD RestoreFrameStateFor(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState,
nsIStatefulFrame::SpecialStateID aID = nsIStatefulFrame::eNoID) = 0;
/**
* Gets a property value for a given frame.

View File

@ -369,7 +369,7 @@ public:
* Get and set the history state for the current document
*/
NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState) = 0;
NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage = PR_FALSE) = 0;
NS_IMETHOD GetHistoryState(nsILayoutHistoryState** aLayoutHistoryState) = 0;
NS_IMETHOD SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState) = 0;

View File

@ -62,8 +62,7 @@ class nsListControlFrame : public nsScrollFrame,
public nsIDOMMouseListener,
public nsIDOMMouseMotionListener,
public nsIDOMKeyListener,
public nsISelectControlFrame,
public nsIStatefulFrame
public nsISelectControlFrame
{
public:
friend nsresult NS_NewListControlFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame);

View File

@ -248,12 +248,22 @@ public:
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
// Capture state from the entire frame heirarchy and store in aState
NS_IMETHOD CaptureFrameState(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState);
NS_IMETHOD RestoreFrameState(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState);
// Add/restore state for one frame (special, global type, like scroll position)
NS_IMETHOD CaptureFrameStateFor(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState,
nsIStatefulFrame::SpecialStateID aID = nsIStatefulFrame::eNoID);
NS_IMETHOD RestoreFrameStateFor(nsIPresContext* aPresContext,
nsIFrame* aFrame,
nsILayoutHistoryState* aState,
nsIStatefulFrame::SpecialStateID aID = nsIStatefulFrame::eNoID);
// Gets and sets properties on a given frame
NS_IMETHOD GetFrameProperty(nsIFrame* aFrame,
@ -1477,8 +1487,10 @@ FrameManager::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
return rv;
}
static nsresult
CaptureFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState)
// Capture state for a given frame.
// Accept a content id here, in some cases we may not have content (scroll position)
NS_IMETHODIMP
FrameManager::CaptureFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState, nsIStatefulFrame::SpecialStateID aID)
{
nsresult rv = NS_OK;
NS_PRECONDITION(nsnull != aFrame && nsnull != aState, "null parameters passed in");
@ -1488,23 +1500,31 @@ CaptureFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHi
nsIStatefulFrame* statefulFrame = nsnull;
aFrame->QueryInterface(NS_GET_IID(nsIStatefulFrame), (void**) &statefulFrame);
if (nsnull != statefulFrame) {
// If so, get the content ID, state type and the state and
// add an association between (ID, type) and (state) to the
// history state storage object, aState.
nsCOMPtr<nsIContent> content;
rv = aFrame->GetContent(getter_AddRefs(content));
if (NS_SUCCEEDED(rv)) {
PRUint32 ID;
rv = content->GetContentID(&ID);
if (NS_SUCCEEDED(rv) && ID) { // Must have ID (don't do anonymous content)
nsIStatefulFrame::StateType type = nsIStatefulFrame::eNoType;
rv = statefulFrame->GetStateType(aPresContext, &type);
// If not given one, get the content ID
PRUint32 ID = aID;
if (nsIStatefulFrame::eNoID == ID) {
nsCOMPtr<nsIContent> content;
rv = aFrame->GetContent(getter_AddRefs(content));
if (NS_SUCCEEDED(rv) && content) {
rv = content->GetContentID(&ID);
}
}
if (NS_SUCCEEDED(rv) && ID) { // Must have ID (don't do anonymous content)
// Get the state type
nsIStatefulFrame::StateType type = nsIStatefulFrame::eNoType;
rv = statefulFrame->GetStateType(aPresContext, &type);
if (NS_SUCCEEDED(rv)) {
// Get the state
nsCOMPtr<nsIPresState> frameState;
rv = statefulFrame->SaveState(aPresContext, getter_AddRefs(frameState));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPresState> frameState;
rv = statefulFrame->SaveState(aPresContext, getter_AddRefs(frameState));
if (NS_SUCCEEDED(rv)) {
rv = aState->AddState(ID, frameState, type);
}
// add an association between (ID, type) and (state) to the
// history state storage object, aState.
rv = aState->AddState(ID, frameState, type);
}
}
}
@ -1539,8 +1559,10 @@ FrameManager::CaptureFrameState(nsIPresContext* aPresContext, nsIFrame* aFrame,
return rv;
}
static nsresult
RestoreFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState)
// Restore state for a given frame.
// Accept a content id here, in some cases we may not have content (scroll position)
NS_IMETHODIMP
FrameManager::RestoreFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState, nsIStatefulFrame::SpecialStateID aID)
{
nsresult rv = NS_OK;
NS_PRECONDITION(nsnull != aFrame && nsnull != aState, "null parameters passed in");
@ -1550,26 +1572,30 @@ RestoreFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHi
nsIStatefulFrame* statefulFrame = nsnull;
aFrame->QueryInterface(NS_GET_IID(nsIStatefulFrame), (void**) &statefulFrame);
if (nsnull != statefulFrame) {
// If so, get the content ID, state type and the frame state and
// ask the frame object to restore its state.
nsCOMPtr<nsIContent> content;
rv = aFrame->GetContent(getter_AddRefs(content));
if (NS_SUCCEEDED(rv)) {
PRUint32 ID;
rv = content->GetContentID(&ID);
if (NS_SUCCEEDED(rv) && ID) { // Must have ID (don't do anonymous content)
nsIStatefulFrame::StateType type = nsIStatefulFrame::eNoType;
rv = statefulFrame->GetStateType(aPresContext, &type);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPresState> frameState;
rv = aState->GetState(ID, getter_AddRefs(frameState), type);
if (NS_SUCCEEDED(rv) && frameState) {
// First restore the state.
rv = statefulFrame->RestoreState(aPresContext, frameState);
// Now remove the state from the state table.
aState->RemoveState(ID, type);
}
// If not given one, get the content ID
PRUint32 ID = aID;
if (nsIStatefulFrame::eNoID == ID) {
nsCOMPtr<nsIContent> content;
rv = aFrame->GetContent(getter_AddRefs(content));
if (NS_SUCCEEDED(rv) && content) {
rv = content->GetContentID(&ID);
}
}
if (NS_SUCCEEDED(rv) && ID) { // Must have ID (don't do anonymous content)
nsIStatefulFrame::StateType type = nsIStatefulFrame::eNoType;
rv = statefulFrame->GetStateType(aPresContext, &type);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPresState> frameState;
rv = aState->GetState(ID, getter_AddRefs(frameState), type);
if (NS_SUCCEEDED(rv) && frameState) {
// First restore the state.
rv = statefulFrame->RestoreState(aPresContext, frameState);
// Now remove the state from the state table.
aState->RemoveState(ID, type);
}
}
}

View File

@ -642,7 +642,7 @@ public:
NS_IMETHOD DoCopy();
NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState);
NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage);
NS_IMETHOD GetHistoryState(nsILayoutHistoryState** aLayoutHistoryState);
NS_IMETHOD SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState);
@ -1543,6 +1543,45 @@ PresShell::NotifyReflowObservers(const char *aData)
return NS_OK;
}
static nsresult
GetRootScrollFrame(nsIPresContext* aPresContext, nsIFrame* aRootFrame, nsIFrame** aScrollFrame) {
// Frames: viewport->scroll->scrollport (Gfx) or viewport->scroll (Native)
// Types: viewport->scroll->sroll viewport->scroll
// Ensure root frame is a viewport frame
*aScrollFrame = nsnull;
nsIFrame* theFrame = nsnull;
if (aRootFrame) {
nsCOMPtr<nsIAtom> fType;
aRootFrame->GetFrameType(getter_AddRefs(fType));
if (fType && (nsLayoutAtoms::viewportFrame == fType.get())) {
// If child is scrollframe keep it (native)
aRootFrame->FirstChild(aPresContext, nsnull, &theFrame);
if (theFrame) {
nsCOMPtr<nsIAtom> fType;
theFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::scrollFrame == fType.get()) {
*aScrollFrame = theFrame;
// If the first child of that is scrollframe, use it instead (gfx)
theFrame->FirstChild(aPresContext, nsnull, &theFrame);
if (theFrame) {
nsCOMPtr<nsIAtom> fType;
theFrame->GetFrameType(getter_AddRefs(fType));
if (nsLayoutAtoms::scrollFrame == fType.get()) {
*aScrollFrame = theFrame;
}
}
}
}
}
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
{
@ -2237,6 +2276,18 @@ PresShell::BeginLoad(nsIDocument *aDocument)
NS_IMETHODIMP
PresShell::EndLoad(nsIDocument *aDocument)
{
// Restore frame state for the root scroll frame
nsIFrame* rootFrame = nsnull;
GetRootFrame(&rootFrame);
if (rootFrame && mHistoryState) {
nsIFrame* scrollFrame = nsnull;
GetRootScrollFrame(mPresContext, rootFrame, &scrollFrame);
if (scrollFrame) {
mFrameManager->RestoreFrameStateFor(mPresContext, scrollFrame, mHistoryState, nsIStatefulFrame::eDocumentScrollState);
}
}
#ifdef MOZ_PERF_METRICS
// Dump reflow, style resolution and frame construction times here.
MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::EndLoad(), this=%p\n", this));
@ -2814,7 +2865,7 @@ PresShell::DoCopy()
}
NS_IMETHODIMP
PresShell::CaptureHistoryState(nsILayoutHistoryState** aState)
PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPage)
{
nsresult rv = NS_OK;
@ -2840,6 +2891,18 @@ PresShell::CaptureHistoryState(nsILayoutHistoryState** aState)
nsIFrame* rootFrame = nsnull;
rv = GetRootFrame(&rootFrame);
if (NS_FAILED(rv) || nsnull == rootFrame) return rv;
// Capture frame state for the root scroll frame
// Don't capture state when first creating doc element heirarchy
// As the scroll position is 0 and this will cause us to loose
// our previously saved place!
if (aLeavingPage) {
nsIFrame* scrollFrame = nsnull;
rv = GetRootScrollFrame(mPresContext, rootFrame, &scrollFrame);
if (scrollFrame) {
rv = mFrameManager->CaptureFrameStateFor(mPresContext, scrollFrame, mHistoryState, nsIStatefulFrame::eDocumentScrollState);
}
}
rv = mFrameManager->CaptureFrameState(mPresContext, rootFrame, mHistoryState);

View File

@ -41,7 +41,10 @@
#include "nsIBox.h"
#include "nsIScrollableFrame.h"
#include "nsIScrollable.h"
#include "nsIStatefulFrame.h"
#include "nsBoxLayoutState.h"
#include "nsISupportsPrimitives.h"
#include "nsIPresState.h"
#undef NOISY_SECOND_REFLOW
@ -267,6 +270,10 @@ nsScrollFrame::QueryInterface(REFNSIID aIID, void** aInstancePtr)
*aInstancePtr = (void*)(nsIScrollableFrame*) this;
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIStatefulFrame))) {
*aInstancePtr = (void*)(nsIStatefulFrame*) this;
return NS_OK;
}
return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr);
@ -976,6 +983,132 @@ nsScrollFrame::GetSkipSides() const
return 0;
}
//----------------------------------------------------------------------
// nsIStatefulFrame
//----------------------------------------------------------------------
NS_IMETHODIMP
nsScrollFrame::GetStateType(nsIPresContext* aPresContext,
nsIStatefulFrame::StateType* aStateType)
{
*aStateType = nsIStatefulFrame::eScrollType;
return NS_OK;
}
//----------------------------------------------------------------------
NS_IMETHODIMP
nsScrollFrame::SaveState(nsIPresContext* aPresContext,
nsIPresState** aState)
{
nsresult res = NS_OK;
PRInt32 x,y;
nsIScrollableView* scrollingView;
nsIView* view;
GetView(aPresContext, &view);
if (NS_SUCCEEDED(view->QueryInterface(kScrollViewIID, (void**)&scrollingView))) {
scrollingView->GetScrollPosition(x,y);
}
nsIView* child = nsnull;
nsRect childRect(0,0,0,0);
if (NS_SUCCEEDED(scrollingView->GetScrolledView(child)) && child) {
child->GetBounds(childRect);
}
res = NS_NewPresState(aState);
nsCOMPtr<nsISupportsPRInt32> xoffset;
if (NS_SUCCEEDED(res)) {
res = nsComponentManager::CreateInstance(NS_SUPPORTS_PRINT32_PROGID,
nsnull, NS_GET_IID(nsISupportsPRInt32), (void**)getter_AddRefs(xoffset));
if (NS_SUCCEEDED(res) && xoffset) {
res = xoffset->SetData(x);
if (NS_SUCCEEDED(res)) {
(*aState)->SetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("x-offset"), xoffset);
}
}
}
nsCOMPtr<nsISupportsPRInt32> yoffset;
if (NS_SUCCEEDED(res)) {
res = nsComponentManager::CreateInstance(NS_SUPPORTS_PRINT32_PROGID,
nsnull, NS_GET_IID(nsISupportsPRInt32), (void**)getter_AddRefs(yoffset));
if (NS_SUCCEEDED(res) && yoffset) {
res = yoffset->SetData(y);
if (NS_SUCCEEDED(res)) {
(*aState)->SetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("y-offset"), yoffset);
}
}
}
nsCOMPtr<nsISupportsPRInt32> width;
if (NS_SUCCEEDED(res)) {
res = nsComponentManager::CreateInstance(NS_SUPPORTS_PRINT32_PROGID,
nsnull, NS_GET_IID(nsISupportsPRInt32), (void**)getter_AddRefs(width));
if (NS_SUCCEEDED(res) && width) {
res = width->SetData(childRect.width);
if (NS_SUCCEEDED(res)) {
(*aState)->SetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("width"), width);
}
}
}
nsCOMPtr<nsISupportsPRInt32> height;
if (NS_SUCCEEDED(res)) {
res = nsComponentManager::CreateInstance(NS_SUPPORTS_PRINT32_PROGID,
nsnull, NS_GET_IID(nsISupportsPRInt32), (void**)getter_AddRefs(height));
if (NS_SUCCEEDED(res) && height) {
res = height->SetData(childRect.height);
if (NS_SUCCEEDED(res)) {
(*aState)->SetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("height"), height);
}
}
}
return res;
}
//-----------------------------------------------------------
NS_IMETHODIMP
nsScrollFrame::RestoreState(nsIPresContext* aPresContext,
nsIPresState* aState)
{
nsCOMPtr<nsISupportsPRInt32> xoffset;
nsCOMPtr<nsISupportsPRInt32> yoffset;
nsCOMPtr<nsISupportsPRInt32> width;
nsCOMPtr<nsISupportsPRInt32> height;
aState->GetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("x-offset"), getter_AddRefs(xoffset));
aState->GetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("y-offset"), getter_AddRefs(yoffset));
aState->GetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("width"), getter_AddRefs(width));
aState->GetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("height"), getter_AddRefs(height));
nsresult res = NS_ERROR_NULL_POINTER;
if (xoffset && yoffset) {
PRInt32 x,y,w,h;
res = xoffset->GetData(&x);
if (NS_SUCCEEDED(res))
res = yoffset->GetData(&y);
if (NS_SUCCEEDED(res))
res = width->GetData(&w);
if (NS_SUCCEEDED(res))
res = height->GetData(&h);
if (NS_SUCCEEDED(res)) {
nsIScrollableView* scrollingView;
nsIView* view;
GetView(aPresContext, &view);
if (NS_SUCCEEDED(view->QueryInterface(kScrollViewIID, (void**)&scrollingView))) {
nsIView* child = nsnull;
nsRect childRect(0,0,0,0);
if (NS_SUCCEEDED(scrollingView->GetScrolledView(child)) && child) {
child->GetBounds(childRect);
}
x = (int)(((float)childRect.width / w) * x);
y = (int)(((float)childRect.height / h) * y);
scrollingView->ScrollTo(x,y,0);
}
}
}
return res;
}
NS_IMETHODIMP
nsScrollFrame::GetFrameType(nsIAtom** aType) const
{

View File

@ -24,6 +24,7 @@
#include "nsHTMLContainerFrame.h"
#include "nsIScrollableFrame.h"
#include "nsIStatefulFrame.h"
/**
* The scroll frame creates and manages the scrolling view
@ -35,7 +36,9 @@
* or remove the scrolled frame
*/
class nsScrollFrame : public nsHTMLContainerFrame,
public nsIScrollableFrame {
public nsIScrollableFrame,
public nsIStatefulFrame
{
public:
friend nsresult NS_NewScrollFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame);
@ -130,6 +133,11 @@ public:
NS_IMETHOD SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
#endif
//nsIStatefulFrame
NS_IMETHOD GetStateType(nsIPresContext* aPresContext, nsIStatefulFrame::StateType* aStateType);
NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState);
NS_IMETHOD RestoreState(nsIPresContext* aPresContext, nsIPresState* aState);
protected:
nsScrollFrame();
virtual PRIntn GetSkipSides() const;

View File

@ -40,6 +40,9 @@
#include "nsIBox.h"
#include "nsBoxLayoutState.h"
#include "nsIBoxToBlockAdaptor.h"
#include "nsIStatefulFrame.h"
#include "nsISupportsPrimitives.h"
#include "nsIPresState.h"
/*
@ -459,6 +462,132 @@ nsScrollPortFrame::GetContentOf(nsIContent** aContent)
return GetContent(aContent);
}
//----------------------------------------------------------------------
// nsIStatefulFrame
//----------------------------------------------------------------------
NS_IMETHODIMP
nsScrollPortFrame::GetStateType(nsIPresContext* aPresContext,
nsIStatefulFrame::StateType* aStateType)
{
*aStateType = nsIStatefulFrame::eScrollType;
return NS_OK;
}
//----------------------------------------------------------------------
NS_IMETHODIMP
nsScrollPortFrame::SaveState(nsIPresContext* aPresContext,
nsIPresState** aState)
{
nsresult res = NS_OK;
PRInt32 x,y;
nsIScrollableView* scrollingView;
nsIView* view;
GetView(aPresContext, &view);
if (NS_SUCCEEDED(view->QueryInterface(kScrollViewIID, (void**)&scrollingView))) {
scrollingView->GetScrollPosition(x,y);
}
nsIView* child = nsnull;
nsRect childRect(0,0,0,0);
if (NS_SUCCEEDED(scrollingView->GetScrolledView(child)) && child) {
child->GetBounds(childRect);
}
res = NS_NewPresState(aState);
nsCOMPtr<nsISupportsPRInt32> xoffset;
if (NS_SUCCEEDED(res)) {
res = nsComponentManager::CreateInstance(NS_SUPPORTS_PRINT32_PROGID,
nsnull, NS_GET_IID(nsISupportsPRInt32), (void**)getter_AddRefs(xoffset));
if (NS_SUCCEEDED(res) && xoffset) {
res = xoffset->SetData(x);
if (NS_SUCCEEDED(res)) {
(*aState)->SetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("x-offset"), xoffset);
}
}
}
nsCOMPtr<nsISupportsPRInt32> yoffset;
if (NS_SUCCEEDED(res)) {
res = nsComponentManager::CreateInstance(NS_SUPPORTS_PRINT32_PROGID,
nsnull, NS_GET_IID(nsISupportsPRInt32), (void**)getter_AddRefs(yoffset));
if (NS_SUCCEEDED(res) && yoffset) {
res = yoffset->SetData(y);
if (NS_SUCCEEDED(res)) {
(*aState)->SetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("y-offset"), yoffset);
}
}
}
nsCOMPtr<nsISupportsPRInt32> width;
if (NS_SUCCEEDED(res)) {
res = nsComponentManager::CreateInstance(NS_SUPPORTS_PRINT32_PROGID,
nsnull, NS_GET_IID(nsISupportsPRInt32), (void**)getter_AddRefs(width));
if (NS_SUCCEEDED(res) && width) {
res = width->SetData(childRect.width);
if (NS_SUCCEEDED(res)) {
(*aState)->SetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("width"), width);
}
}
}
nsCOMPtr<nsISupportsPRInt32> height;
if (NS_SUCCEEDED(res)) {
res = nsComponentManager::CreateInstance(NS_SUPPORTS_PRINT32_PROGID,
nsnull, NS_GET_IID(nsISupportsPRInt32), (void**)getter_AddRefs(height));
if (NS_SUCCEEDED(res) && height) {
res = height->SetData(childRect.height);
if (NS_SUCCEEDED(res)) {
(*aState)->SetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("height"), height);
}
}
}
return res;
}
//-----------------------------------------------------------
NS_IMETHODIMP
nsScrollPortFrame::RestoreState(nsIPresContext* aPresContext,
nsIPresState* aState)
{
nsCOMPtr<nsISupportsPRInt32> xoffset;
nsCOMPtr<nsISupportsPRInt32> yoffset;
nsCOMPtr<nsISupportsPRInt32> width;
nsCOMPtr<nsISupportsPRInt32> height;
aState->GetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("x-offset"), getter_AddRefs(xoffset));
aState->GetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("y-offset"), getter_AddRefs(yoffset));
aState->GetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("width"), getter_AddRefs(width));
aState->GetStatePropertyAsSupports(NS_ConvertASCIItoUCS2("height"), getter_AddRefs(height));
nsresult res = NS_ERROR_NULL_POINTER;
if (xoffset && yoffset) {
PRInt32 x,y,w,h;
res = xoffset->GetData(&x);
if (NS_SUCCEEDED(res))
res = yoffset->GetData(&y);
if (NS_SUCCEEDED(res))
res = width->GetData(&w);
if (NS_SUCCEEDED(res))
res = height->GetData(&h);
if (NS_SUCCEEDED(res)) {
nsIScrollableView* scrollingView;
nsIView* view;
GetView(aPresContext, &view);
if (NS_SUCCEEDED(view->QueryInterface(kScrollViewIID, (void**)&scrollingView))) {
nsIView* child = nsnull;
nsRect childRect(0,0,0,0);
if (NS_SUCCEEDED(scrollingView->GetScrolledView(child)) && child) {
child->GetBounds(childRect);
}
x = (int)(((float)childRect.width / w) * x);
y = (int)(((float)childRect.height / h) * y);
scrollingView->ScrollTo(x,y,0);
}
}
}
return res;
}
NS_IMETHODIMP
nsScrollPortFrame::GetFrameType(nsIAtom** aType) const
{
@ -490,6 +619,7 @@ nsScrollPortFrame::Release(void)
NS_INTERFACE_MAP_BEGIN(nsScrollPortFrame)
NS_INTERFACE_MAP_ENTRY(nsIBox)
NS_INTERFACE_MAP_ENTRY(nsIStatefulFrame)
#ifdef NS_DEBUG
NS_INTERFACE_MAP_ENTRY(nsIFrameDebug)
#endif

View File

@ -23,6 +23,8 @@
#define nsScrollPortFrame_h___
#include "nsBoxFrame.h"
#include "nsIStatefulFrame.h"
/**
* The scroll frame creates and manages the scrolling view
@ -33,7 +35,8 @@
* Scroll frames don't support incremental changes, i.e. you can't replace
* or remove the scrolled frame
*/
class nsScrollPortFrame : nsBoxFrame {
class nsScrollPortFrame : nsBoxFrame,
public nsIStatefulFrame {
public:
friend nsresult NS_NewScrollPortFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame);
@ -99,6 +102,12 @@ public:
virtual nsresult GetContentOf(nsIContent** aContent);
//nsIStatefulFrame
NS_IMETHOD GetStateType(nsIPresContext* aPresContext, nsIStatefulFrame::StateType* aStateType);
NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState);
NS_IMETHOD RestoreState(nsIPresContext* aPresContext, nsIPresState* aState);
protected:
nsScrollPortFrame(nsIPresShell* aShell);
virtual PRIntn GetSkipSides() const;

View File

@ -62,8 +62,7 @@ class nsListControlFrame : public nsScrollFrame,
public nsIDOMMouseListener,
public nsIDOMMouseMotionListener,
public nsIDOMKeyListener,
public nsISelectControlFrame,
public nsIStatefulFrame
public nsISelectControlFrame
{
public:
friend nsresult NS_NewListControlFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame);