From cc5c98e1d32388731962a5685088d0b6bceee3fb Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Fri, 1 Dec 2017 07:18:53 -0500 Subject: [PATCH] Bug 1420648 - Ensure WebRender computes the snapped image decode size the same as the fallback path. r=tnikkel --- gfx/layers/wr/StackingContextHelper.cpp | 3 +- gfx/layers/wr/StackingContextHelper.h | 6 +++ layout/base/nsLayoutUtils.cpp | 52 +++++++++++++++++++++---- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/gfx/layers/wr/StackingContextHelper.cpp b/gfx/layers/wr/StackingContextHelper.cpp index 1afe49614b80..ac3e7c2aad90 100644 --- a/gfx/layers/wr/StackingContextHelper.cpp +++ b/gfx/layers/wr/StackingContextHelper.cpp @@ -40,7 +40,8 @@ StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParen // Compute scale for fallback rendering. gfx::Matrix transform2d; if (aBoundTransform && aBoundTransform->CanDraw2D(&transform2d)) { - mScale = transform2d.ScaleFactors(true) * aParentSC.mScale; + mInheritedTransform = transform2d * aParentSC.mInheritedTransform; + mScale = mInheritedTransform.ScaleFactors(true); } mBuilder->PushStackingContext(wr::LayoutRect(), diff --git a/gfx/layers/wr/StackingContextHelper.h b/gfx/layers/wr/StackingContextHelper.h index 98691f8d681d..a2040193d779 100644 --- a/gfx/layers/wr/StackingContextHelper.h +++ b/gfx/layers/wr/StackingContextHelper.h @@ -68,6 +68,11 @@ public: // Export the inherited scale gfx::Size GetInheritedScale() const { return mScale; } + const gfx::Matrix& GetInheritedTransform() const + { + return mInheritedTransform; + } + bool IsBackfaceVisible() const { return mTransform.IsBackfaceVisible(); } private: @@ -75,6 +80,7 @@ private: LayoutDevicePoint mOrigin; gfx::Matrix4x4 mTransform; gfx::Size mScale; + gfx::Matrix mInheritedTransform; }; } // namespace layers diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 07aecb8b761d..19e249e11b05 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -6766,6 +6766,8 @@ ComputeSnappedImageDrawingParameters(gfxContext* aCtx, // Snap even if we have a scale in the context. But don't snap if // we have something that's not translation+scale, or if the scale flips in // the X or Y direction, because snapped image drawing can't handle that yet. + // Any changes to this algorithm will need to be reflected in + // ComputeImageContainerDrawingParameters. if (!currentMatrix.HasNonAxisAlignedTransform() && currentMatrix._11 > 0.0 && currentMatrix._22 > 0.0 && aCtx->UserToDevicePixelSnapped(fill, true) && @@ -7191,15 +7193,49 @@ nsLayoutUtils::ComputeImageContainerDrawingParameters(imgIContainer* viewportSize.height))); } - // Compute our size in layer pixels. - const LayerIntSize layerSize = - RoundedToInt(LayerSize(aDestRect.Width() * scaleFactors.width, - aDestRect.Height() * scaleFactors.height)); + // Attempt to snap pixels, the same as ComputeSnappedImageDrawingParameters. + // Any changes to the algorithm here will need to be reflected there. + bool snapped = false; + gfxSize gfxLayerSize; + const gfx::Matrix& itm = aSc.GetInheritedTransform(); + if (!itm.HasNonAxisAlignedTransform() && + itm._11 > 0.0 && + itm._22 > 0.0) { + gfxRect rect(gfxPoint(aDestRect.X(), aDestRect.Y()), + gfxSize(aDestRect.Width(), aDestRect.Height())); + + gfxPoint p1 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopLeft()))); + gfxPoint p2 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopRight()))); + gfxPoint p3 = ThebesPoint(itm.TransformPoint(ToPoint(rect.BottomRight()))); + + if (p2 == gfxPoint(p1.x, p3.y) || p2 == gfxPoint(p3.x, p1.y)) { + p1.Round(); + p3.Round(); + + rect.MoveTo(gfxPoint(std::min(p1.x, p3.x), std::min(p1.y, p3.y))); + rect.SizeTo(gfxSize(std::max(p1.x, p3.x) - rect.X(), + std::max(p1.y, p3.y) - rect.Y())); + + // An empty size is unacceptable so we ensure our suggested size is at + // least 1 pixel wide/tall. + gfxLayerSize = gfxSize(std::max(rect.Width(), 1.0), + std::max(rect.Height(), 1.0)); + snapped = true; + } + } + + if (!snapped) { + // Compute our size in layer pixels. + const LayerIntSize layerSize = + RoundedToInt(LayerSize(aDestRect.Width() * scaleFactors.width, + aDestRect.Height() * scaleFactors.height)); + + // An empty size is unacceptable so we ensure our suggested size is at least + // 1 pixel wide/tall. + gfxLayerSize = gfxSize(std::max(layerSize.width, 1), + std::max(layerSize.height, 1)); + } - // Determine the optimal image size to use. An empty size is unacceptable so - // we ensure our suggested size is at least 1 pixel wide/tall. - gfxSize gfxLayerSize = gfxSize(std::max(layerSize.width, 1), - std::max(layerSize.height, 1)); return aImage->OptimalImageSizeForDest(gfxLayerSize, imgIContainer::FRAME_CURRENT, samplingFilter, aFlags);