Bug 1255068 - Do not allow empty transaction transform changes if the scroll position has changed since the last paint. r?kats, r?mattwoodrow draft
authorMarkus Stange <mstange@themasta.com>
Fri, 11 Mar 2016 15:35:35 -0500
changeset 339623 8c39373fdb609516591e8aafeea4d9e3e02ed974
parent 339620 f3e82bb7dc857c1c5e7dc7e349597132c1f8c0e0
child 516025 390e91b9e723d01d58bd6b394fe2185693cd7969
push id12770
push usermstange@themasta.com
push dateFri, 11 Mar 2016 21:07:06 +0000
reviewerskats, mattwoodrow
bugs1255068
milestone48.0a1
Bug 1255068 - Do not allow empty transaction transform changes if the scroll position has changed since the last paint. r?kats, r?mattwoodrow MozReview-Commit-ID: 7exuhuf3HTJ
layout/generic/nsFrame.cpp
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -5267,28 +5267,67 @@ nsIFrame::InvalidateFrameWithRect(const 
     AddStateBits(NS_FRAME_HAS_INVALID_RECT);
   }
 
   *rect = rect->Union(aRect);
 }
 
 /*static*/ uint8_t nsIFrame::sLayerIsPrerenderedDataKey;
 
+static bool
+DoesLayerHaveOutOfDateFrameMetrics(Layer* aLayer)
+{
+  for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
+    const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
+    nsIScrollableFrame* scrollableFrame =
+      nsLayoutUtils::FindScrollableFrameFor(metrics.GetScrollId());
+    if (!scrollableFrame) {
+      // I don't know how this could happen, but let's do the safe thing and
+      // trigger a full paint in this case.
+      return true;
+    }
+    nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
+    if (metrics.GetScrollOffset() != CSSPoint::FromAppUnits(scrollPosition)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool
+DoesLayerOrAncestorsHaveOutOfDateFrameMetrics(Layer* aLayer)
+{
+  for (Layer* layer = aLayer; layer; layer = layer->GetParent()) {
+    if (DoesLayerHaveOutOfDateFrameMetrics(layer)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 bool
 nsIFrame::TryUpdateTransformOnly(Layer** aLayerResult)
 {
   Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
     this, nsDisplayItem::TYPE_TRANSFORM);
   if (!layer || !layer->HasUserData(LayerIsPrerenderedDataKey())) {
     // If this layer isn't prerendered or we clip composites to our OS
     // window, then we can't correctly optimize to an empty
     // transaction in general.
     return false;
   }
 
+  if (DoesLayerOrAncestorsHaveOutOfDateFrameMetrics(layer)) {
+    // At least one scroll frame that can affect the position of this layer
+    // has changed its scroll offset since the last paint. Schedule a full
+    // paint to make sure that this layer's transform and all the frame
+    // metrics that affect it are in sync.
+    return false;
+  }
+
   gfx::Matrix4x4 transform3d;
   if (!nsLayoutUtils::GetLayerTransformForFrame(this, &transform3d)) {
     // We're not able to compute a layer transform that we know would
     // be used at the next layers transaction, so we can't only update
     // the transform and will need to schedule an invalidating paint.
     return false;
   }
   gfx::Matrix transform;