Bug 1039818 - Do not allow an older APZ repaint request to clobber a newer pres shell resolution in Layout. r=kats
authorBotond Ballo <botond@mozilla.com>
Fri, 10 Apr 2015 19:34:23 -0400
changeset 238899 6816cc58e19bf4ede146db9743acfc363b273158
parent 238898 dfdb7109538db49f6ca1e39fc0bdda5bc4ed059d
child 238900 a872ba7db8a40b81c3d29b95fd8e15de80e957c7
push idunknown
push userunknown
push dateunknown
reviewerskats
bugs1039818
milestone40.0a1
Bug 1039818 - Do not allow an older APZ repaint request to clobber a newer pres shell resolution in Layout. r=kats
dom/ipc/TabChild.cpp
gfx/layers/apz/util/APZCCallbackHelper.cpp
gfx/layers/apz/util/APZCCallbackHelper.h
widget/windows/winrt/APZController.cpp
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -514,17 +514,20 @@ TabChildBase::ProcessUpdateFrame(const F
 {
     if (!mGlobal || !mTabChildGlobal) {
         return aFrameMetrics;
     }
 
     nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
 
     FrameMetrics newMetrics = aFrameMetrics;
-    APZCCallbackHelper::UpdateRootFrame(utils, newMetrics);
+    nsCOMPtr<nsIDocument> doc = GetDocument();
+    if (doc && doc->GetShell()) {
+      APZCCallbackHelper::UpdateRootFrame(utils, doc->GetShell(), newMetrics);
+    }
 
     CSSSize cssCompositedSize = newMetrics.CalculateCompositedSizeInCssPixels();
     // The BrowserElementScrolling helper must know about these updated metrics
     // for other functions it performs, such as double tap handling.
     // Note, %f must not be used because it is locale specific!
     nsString data;
     data.AppendPrintf("{ \"x\" : %d", NS_lround(newMetrics.GetScrollOffset().x));
     data.AppendPrintf(", \"y\" : %d", NS_lround(newMetrics.GetScrollOffset().y));
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -176,25 +176,37 @@ SetDisplayPortMargins(nsIDOMWindowUtils*
   nsRect base(0, 0,
               baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(),
               baseCSS.height * nsPresContext::AppUnitsPerCSSPixel());
   nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base);
 }
 
 void
 APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
+                                    nsIPresShell* aPresShell,
                                     FrameMetrics& aMetrics)
 {
   // Precondition checks
   MOZ_ASSERT(aUtils);
+  MOZ_ASSERT(aPresShell);
   MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());
   if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
     return;
   }
 
+  float presShellResolution = nsLayoutUtils::GetResolution(aPresShell);
+
+  // If the pres shell resolution has changed on the content side side
+  // the time this repaint request was fired, consider this request out of date
+  // and drop it; setting a zoom based on the out-of-date resolution can have
+  // the effect of getting us stuck with the stale resolution.
+  if (presShellResolution != aMetrics.GetPresShellResolution()) {
+    return;
+  }
+
   // Set the scroll port size, which determines the scroll range. For example if
   // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would
   // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent
   // overscroll). Note that if the content here was zoomed to 2x, the document would
   // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum
   // scroll range would be 900. Therefore this calculation depends on the zoom applied
   // to the content relative to the container.
   // Note that this needs to happen before scrolling the frame (in UpdateFrameCommon),
@@ -202,18 +214,18 @@ APZCCallbackHelper::UpdateRootFrame(nsID
   CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels();
   aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);
 
   nsIContent* content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
   ScrollFrame(content, aMetrics);
 
   // The pres shell resolution is updated by the the async zoom since the
   // last paint.
-  float presShellResolution = aMetrics.GetPresShellResolution()
-                            * aMetrics.GetAsyncZoom().scale;
+  presShellResolution = aMetrics.GetPresShellResolution()
+                      * aMetrics.GetAsyncZoom().scale;
   aUtils->SetResolutionAndScaleTo(presShellResolution);
 
   SetDisplayPortMargins(aUtils, content, aMetrics);
 }
 
 void
 APZCCallbackHelper::UpdateSubFrame(nsIContent* aContent,
                                    FrameMetrics& aMetrics)
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -61,16 +61,17 @@ public:
 
     /* Applies the scroll and zoom parameters from the given FrameMetrics object to
        the root frame corresponding to the given DOMWindowUtils. If tiled thebes
        layers are enabled, this will align the displayport to tile boundaries.
        Setting the scroll position can cause some small adjustments to be made
        to the actual scroll position. aMetrics' display port and scroll position
        will be updated with any modifications made. */
     static void UpdateRootFrame(nsIDOMWindowUtils* aUtils,
+                                nsIPresShell* aPresShell,
                                 FrameMetrics& aMetrics);
 
     /* Applies the scroll parameters from the given FrameMetrics object to the subframe
        corresponding to the given content object. If tiled thebes
        layers are enabled, this will align the displayport to tile boundaries.
        Setting the scroll position can cause some small adjustments to be made
        to the actual scroll position. aMetrics' display port and scroll position
        will be updated with any modifications made. */
--- a/widget/windows/winrt/APZController.cpp
+++ b/widget/windows/winrt/APZController.cpp
@@ -168,17 +168,19 @@ APZController::RequestContentRepaint(con
 
   // We're dealing with a tab, call UpdateRootFrame.
   nsCOMPtr<nsIDOMWindowUtils> utils;
   nsCOMPtr<nsIDOMWindow> window = subDocument->GetDefaultView();
   if (window) {
     utils = do_GetInterface(window);
     if (utils) {
       FrameMetrics metrics = aFrameMetrics;
-      mozilla::layers::APZCCallbackHelper::UpdateRootFrame(utils, metrics);
+      if (subDocument->GetShell()) {
+        mozilla::layers::APZCCallbackHelper::UpdateRootFrame(utils, subDocument->GetShell(), metrics);
+      }
 
 #ifdef DEBUG_CONTROLLER
       WinUtils::Log("APZController: %I64d mDisplayPortMargins: %0.2f %0.2f %0.2f %0.2f",
         metrics.GetScrollId(),
         metrics.GetDisplayPortMargins().left,
         metrics.GetDisplayPortMargins().top,
         metrics.GetDisplayPortMargins().right,
         metrics.GetDisplayPortMargins().bottom);