Bug 1324499: Save and restore scroll position after reflow in GetContentSizeInternal draft
authorangelsl <angelsl@in04.sg>
Mon, 21 Aug 2017 21:25:20 +0800
changeset 650178 2e30d7cc8cd996132e10afb02a38331ccba11f7b
parent 649622 7dddbd85047c6dc73ddbe1e423cd643a217845b3
child 727317 dd2f0a93cbec28db9f6af1338d56b40e2f837cd9
push id75290
push userbmo:angelsl@in04.sg
push dateMon, 21 Aug 2017 23:41:40 +0000
bugs1324499
milestone57.0a1
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
layout/base/nsDocumentViewer.cpp
--- 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);