Backed out changeset 3241eaaa608d (bug 1363922)
authorSebastian Hengst <archaeopteryx@coole-files.de>
Sun, 20 Aug 2017 19:20:12 +0200
changeset 649620 2f320a066e55d3b60ef42f4fe6f6d866f688e16d
parent 649619 de22ecdc7ec67f2e6e4186d9f390a73f93e28a53
child 649621 47172ec305228afaa7fff15c8cb3c864954ef14c
push id75073
push userbmo:mozilla@hocat.ca
push dateSun, 20 Aug 2017 22:21:51 +0000
bugs1363922
milestone57.0a1
backs out3241eaaa608dcce34e44818f7e71ef0eeee06feb
Backed out changeset 3241eaaa608d (bug 1363922)
layout/generic/nsGfxScrollFrame.cpp
layout/painting/FrameLayerBuilder.cpp
layout/painting/FrameLayerBuilder.h
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2757,18 +2757,17 @@ ScrollFrameHelper::ScrollToImpl(nsPoint 
     // at all. Default it to some generic placeholder.
     aOrigin = nsGkAtoms::other;
   }
 
   nsPresContext* presContext = mOuter->PresContext();
   nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   // 'scale' is our estimate of the scale factor that will be applied
   // when rendering the scrolled content to its own PaintedLayer.
-  float presShellResolution = mScrolledFrame->PresContext()->PresShell()->GetResolution();
-  gfxSize scale(presShellResolution, presShellResolution);
+  gfxSize scale = FrameLayerBuilder::GetPaintedLayerScaleForFrame(mScrolledFrame);
   nsPoint curPos = GetScrollPosition();
   nsPoint alignWithPos = mScrollPosForLayerPixelAlignment == nsPoint(-1,-1)
                          ? curPos : mScrollPosForLayerPixelAlignment;
   // Try to align aPt with curPos so they have an integer number of layer
   // pixels between them. This gives us the best chance of scrolling without
   // having to invalidate due to changes in subpixel rendering.
   // Note that when we actually draw into a PaintedLayer, the coordinates
   // that get mapped onto the layer buffer pixels are from the display list,
@@ -5875,22 +5874,19 @@ ScrollFrameHelper::GetScrolledRect() con
   nsRect scrollPort(mScrollPort.TopLeft() + toReferenceFrame, scrollPortSize);
   nsRect scrolledRect = result + scrollPort.TopLeft();
 
   if (scrollPort.Overflows() || scrolledRect.Overflows()) {
     return result;
   }
 
   // Now, snap the bottom right corner of both of these rects.
-  // We ignore the CSS transforms here because we don't have a cheap way of accessing layer resolution of
-  // the layer that this frame is going to be painted to. Using the presShell resolution is good enough
-  // for most situations and simpler.
+  // We snap to layer pixels, so we need to respect the layer's scale.
   nscoord appUnitsPerDevPixel = mScrolledFrame->PresContext()->AppUnitsPerDevPixel();
-  float presShellResolution = mScrolledFrame->PresContext()->PresShell()->GetResolution();
-  gfxSize scale(presShellResolution, presShellResolution);
+  gfxSize scale = FrameLayerBuilder::GetPaintedLayerScaleForFrame(mScrolledFrame);
   if (scale.IsEmpty()) {
     scale = gfxSize(1.0f, 1.0f);
   }
 
   // Compute bounds for the scroll position, and computed the snapped scrolled
   // rect from the scroll position bounds.
   nscoord snappedScrolledAreaBottom = SnapCoord(scrolledRect.YMost(), scale.height, appUnitsPerDevPixel);
   nscoord snappedScrollPortBottom = SnapCoord(scrollPort.YMost(), scale.height, appUnitsPerDevPixel);
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -5849,16 +5849,72 @@ FrameLayerBuilder::GetDedicatedLayer(nsI
           !layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
         return layer;
       }
     }
   }
   return nullptr;
 }
 
+static gfxSize
+PredictScaleForContent(nsIFrame* aFrame, nsIFrame* aAncestorWithScale,
+                       const gfxSize& aScale)
+{
+  Matrix4x4 transform = Matrix4x4::Scaling(aScale.width, aScale.height, 1.0);
+  if (aFrame != aAncestorWithScale) {
+    // aTransform is applied first, then the scale is applied to the result
+    transform = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestorWithScale)*transform;
+  }
+  Matrix transform2d;
+  if (transform.CanDraw2D(&transform2d)) {
+     return ThebesMatrix(transform2d).ScaleFactors(true);
+  }
+  return gfxSize(1.0, 1.0);
+}
+
+gfxSize
+FrameLayerBuilder::GetPaintedLayerScaleForFrame(nsIFrame* aFrame)
+{
+  MOZ_ASSERT(aFrame, "need a frame");
+  nsIFrame* last = nullptr;
+  for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
+    last = f;
+
+    if (nsLayoutUtils::IsPopup(f)) {
+      // Don't examine ancestors of a popup. It won't make sense to check
+      // the transform from some content inside the popup to some content
+      // which is an ancestor of the popup.
+      break;
+    }
+
+    const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
+
+    for (uint32_t i = 0; i < array.Length(); i++) {
+      Layer* layer = DisplayItemData::AssertDisplayItemData(array.ElementAt(i))->mLayer;
+      ContainerLayer* container = layer->AsContainerLayer();
+      if (!container ||
+          !layer->Manager()->IsWidgetLayerManager()) {
+        continue;
+      }
+      for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
+        PaintedDisplayItemLayerUserData* data =
+            static_cast<PaintedDisplayItemLayerUserData*>
+              (l->GetUserData(&gPaintedDisplayItemLayerUserData));
+        if (data) {
+          return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale));
+        }
+      }
+    }
+  }
+
+  float presShellResolution = last->PresContext()->PresShell()->GetResolution();
+  return PredictScaleForContent(aFrame, last,
+      gfxSize(presShellResolution, presShellResolution));
+}
+
 #ifdef MOZ_DUMP_PAINTING
 static void DebugPaintItem(DrawTarget& aDrawTarget,
                            nsPresContext* aPresContext,
                            nsDisplayItem *aItem,
                            nsDisplayListBuilder* aBuilder)
 {
   bool snap;
   Rect bounds = NSRectToRect(aItem->GetBounds(aBuilder, &snap),
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -564,16 +564,25 @@ public:
   /**
    * Get the translation transform that was in aLayer when we last painted. It's either
    * the transform saved by SaveLastPaintTransform, or else the transform
    * that's currently in the layer (which must be an integer translation).
    */
   nsIntPoint GetLastPaintOffset(PaintedLayer* aLayer);
 
   /**
+   * Return the resolution at which we expect to render aFrame's contents,
+   * assuming they are being painted to retained layers. This takes into account
+   * the resolution the contents of the ContainerLayer containing aFrame are
+   * being rendered at, as well as any currently-inactive transforms between
+   * aFrame and that container layer.
+   */
+  static gfxSize GetPaintedLayerScaleForFrame(nsIFrame* aFrame);
+
+  /**
    * Stores a Layer as the dedicated layer in the DisplayItemData for a given frame/key pair.
    *
    * Used when we optimize a PaintedLayer into an ImageLayer and want to retroactively update the
    * DisplayItemData so we can retrieve the layer from within layout.
    */
   void StoreOptimizedLayerForFrame(nsDisplayItem* aItem, Layer* aLayer);
 
   static void RemoveFrameFromLayerManager(const nsIFrame* aFrame,