Backed out changeset 3241eaaa608d (
bug 1363922)
--- 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,