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
--- 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;