Bug 1324499: Save and restore scroll position after reflow in GetContentSizeInternal
The bug is caused by the first call to ResizeReflow in
nsDocumentViewer::GetContentSizeInternal, which reflows the content with
unlimited height. ResizeReflow calls DidDoReflow, which calls a
callback installed by nsHTMLScrollFrame that clamps the scroll port setting
the scroll top to 0 and losing the original scroll top. When the content
is reflowed again to the maximum height, the scroll top stays at 0.
MozReview-Commit-ID: 3VkgWLqSTDP
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -3563,31 +3563,44 @@ nsDocumentViewer::GetContentSizeInternal
{
RefPtr<gfxContext> rcx(presShell->CreateReferenceRenderingContext());
prefWidth = root->GetPrefISize(rcx);
}
if (prefWidth > aMaxWidth) {
prefWidth = aMaxWidth;
}
+ nsAutoPtr<nsPresState> frameState;
+ nsIScrollableFrame *scrollFrame = presShell->GetRootScrollFrameAsScrollable();
+ nsIStatefulFrame *statefulFrame = do_QueryFrame(scrollFrame);
+ if (statefulFrame) {
+ statefulFrame->SaveState(getter_Transfers(frameState));
+ }
+
nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<nsPresContext> presContext;
GetPresContext(getter_AddRefs(presContext));
NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
// so how big is it?
nsRect shellArea = presContext->GetVisibleArea();
if (shellArea.height > aMaxHeight) {
// Reflow to max height if we would up too tall.
rv = presShell->ResizeReflow(prefWidth, aMaxHeight);
NS_ENSURE_SUCCESS(rv, rv);
shellArea = presContext->GetVisibleArea();
+
+ // the first reflow reset our scroll, now set it back
+ if (frameState && presShell->GetRootScrollFrameAsScrollable() == scrollFrame) {
+ statefulFrame->RestoreState(frameState);
+ scrollFrame->ScrollToRestoredPosition();
+ }
}
// Protect against bogus returns here
NS_ENSURE_TRUE(shellArea.width != NS_UNCONSTRAINEDSIZE &&
shellArea.height != NS_UNCONSTRAINEDSIZE,
NS_ERROR_FAILURE);
*aWidth = presContext->AppUnitsToDevPixels(shellArea.width);