Bug 1636119 - Don't snap SVG content during animation r=hiro
authorlongsonr <longsonr@gmail.com>
Thu, 14 May 2020 10:43:11 +0000
changeset 529851 02e266dc4a3da99bfd63b091789f2602844870e7
parent 529850 cc2d8256440757af8a1dda8ff37fd8047b44cb44
child 529852 c5841a4c7ab6949519ab442b3459afa5f78fe28e
push id115941
push userlongsonr@gmail.com
push dateThu, 14 May 2020 11:05:52 +0000
treeherderautoland@02e266dc4a3d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershiro
bugs1636119
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1636119 - Don't snap SVG content during animation r=hiro Differential Revision: https://phabricator.services.mozilla.com/D74505
gfx/layers/AnimationHelper.cpp
gfx/layers/AnimationInfo.cpp
gfx/layers/Layers.h
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/ipc/LayersMessages.ipdlh
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/painting/FrameLayerBuilder.cpp
layout/painting/nsDisplayList.cpp
--- a/gfx/layers/AnimationHelper.cpp
+++ b/gfx/layers/AnimationHelper.cpp
@@ -634,17 +634,17 @@ bool AnimationHelper::SampleAnimations(C
         // If the parent has perspective transform, then the offset into
         // reference frame coordinates is already on this transform. If not,
         // then we need to ask for it to be added here.
         const TransformData& transformData =
             *animationStorageData.mTransformData;
         if (!transformData.hasPerspectiveParent()) {
           nsLayoutUtils::PostTranslate(transform, transformData.origin(),
                                        transformData.appUnitsPerDevPixel(),
-                                       true);
+                                       transformData.snapToGrid());
         }
 
         transform.PostScale(transformData.inheritedXScale(),
                             transformData.inheritedYScale(), 1);
 
         aStorage->SetAnimatedValue(iter.Key(), std::move(transform),
                                    std::move(frameTransform), transformData);
         break;
--- a/gfx/layers/AnimationInfo.cpp
+++ b/gfx/layers/AnimationInfo.cpp
@@ -692,33 +692,34 @@ static Maybe<TransformData> CreateAnimat
     // Animations are animated at the coordination of the reference
     // frame outside, not the given frame itself.  The given frame
     // is also reference frame too, so the parent's reference frame
     // are used.
     nsIFrame* referenceFrame = nsLayoutUtils::GetReferenceFrame(
         nsLayoutUtils::GetCrossDocParentFrame(aFrame));
     origin = aFrame->GetOffsetToCrossDoc(referenceFrame);
   }
+  bool snapToGrid = nsLayoutUtils::ShouldSnapToGrid(aFrame);
 
   Maybe<MotionPathData> motionPathData;
   if (aDataType == AnimationDataType::WithMotionPath) {
     const StyleTransformOrigin& styleOrigin =
         aFrame->StyleDisplay()->mTransformOrigin;
     CSSPoint motionPathOrigin = nsStyleTransformMatrix::Convert2DPosition(
         styleOrigin.horizontal, styleOrigin.vertical, refBox);
     CSSPoint anchorAdjustment =
         MotionPathUtils::ComputeAnchorPointAdjustment(*aFrame);
 
     motionPathData = Some(layers::MotionPathData(
         motionPathOrigin, anchorAdjustment, RayReferenceData(aFrame)));
   }
 
   return Some(TransformData(origin, offsetToTransformOrigin, bounds,
                             devPixelsToAppUnits, scaleX, scaleY,
-                            hasPerspectiveParent, motionPathData));
+                            hasPerspectiveParent, snapToGrid, motionPathData));
 }
 
 void AnimationInfo::AddNonAnimatingTransformLikePropertiesStyles(
     const nsCSSPropertyIDSet& aNonAnimatingProperties, nsIFrame* aFrame,
     Send aSendFlag) {
   auto appendFakeAnimation = [this, aSendFlag](nsCSSPropertyID aProperty,
                                                Animatable&& aBaseStyle) {
     layers::Animation* animation = (aSendFlag == Send::NextTransaction)
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -892,17 +892,22 @@ class Layer {
      * only until flattening code is obsoleted. See bug 633097
      */
     CONTENT_DISABLE_FLATTENING = 0x40,
 
     /**
      * This layer is hidden if the backface of the layer is visible
      * to user.
      */
-    CONTENT_BACKFACE_HIDDEN = 0x80
+    CONTENT_BACKFACE_HIDDEN = 0x80,
+
+    /**
+     * This layer should be snapped to the pixel grid.
+     */
+    CONTENT_SNAP_TO_GRID = 0x100
   };
   /**
    * CONSTRUCTION PHASE ONLY
    * This lets layout make some promises about what will be drawn into the
    * visible region of the PaintedLayer. This enables internal quality
    * and performance optimizations.
    */
   void SetContentFlags(uint32_t aFlags) {
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -556,18 +556,20 @@ static Matrix4x4 FrameTransformToTransfo
     const Matrix4x4& aFrameTransform, Layer* aLayer,
     const TransformData& aTransformData) {
   Matrix4x4 transformInDevice = aFrameTransform;
   // If our parent layer is a perspective layer, then the offset into reference
   // frame coordinates is already on that layer. If not, then we need to ask
   // for it to be added here.
   if (!aLayer->GetParent() ||
       !aLayer->GetParent()->GetTransformIsPerspective()) {
-    nsLayoutUtils::PostTranslate(transformInDevice, aTransformData.origin(),
-                                 aTransformData.appUnitsPerDevPixel(), true);
+    nsLayoutUtils::PostTranslate(
+        transformInDevice, aTransformData.origin(),
+        aTransformData.appUnitsPerDevPixel(),
+        aLayer->GetContentFlags() & Layer::CONTENT_SNAP_TO_GRID);
   }
 
   if (ContainerLayer* c = aLayer->AsContainerLayer()) {
     transformInDevice.PostScale(c->GetInheritedXScale(),
                                 c->GetInheritedYScale(), 1);
   }
 
   return transformInDevice;
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -162,16 +162,18 @@ struct TransformData {
   Point3D transformOrigin;
   nsRect bounds;
   int32_t appUnitsPerDevPixel;
   // The resolution scale inherited from the parent
   float inheritedXScale;
   float inheritedYScale;
   // True if the parent has perspective transform
   bool hasPerspectiveParent;
+  // True if the animation should be snapped to the pixel grid
+  bool snapToGrid;
   MotionPathData? motionPathData;
 };
 
 struct Animation {
   // The zero time of this Animation's timeline. May be null if isNotPlaying is
   // true.
   TimeStamp originTime;
   // The start time is relative to the originTime. This allows us to represent
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2587,16 +2587,21 @@ void nsLayoutUtils::PostTranslate(Matrix
               NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel), 0.0f);
   if (aRounded) {
     gfxOrigin.x = NS_round(gfxOrigin.x);
     gfxOrigin.y = NS_round(gfxOrigin.y);
   }
   aTransform.PostTranslate(gfxOrigin);
 }
 
+bool nsLayoutUtils::ShouldSnapToGrid(const nsIFrame* aFrame) {
+  return !aFrame || !aFrame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) ||
+         aFrame->IsSVGOuterSVGAnonChildFrame();
+}
+
 // We want to this return true for the scroll frame, but not the
 // scrolled frame (which has the same content).
 bool nsLayoutUtils::FrameHasDisplayPort(nsIFrame* aFrame,
                                         const nsIFrame* aScrolledFrame) {
   if (!aFrame->GetContent() || !HasDisplayPort(aFrame->GetContent())) {
     return false;
   }
   nsIScrollableFrame* sf = do_QueryFrame(aFrame);
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1047,16 +1047,23 @@ class nsLayoutUtils {
 
   /**
    * Converts app units to pixels (with optional snapping) and appends as a
    * translation to aTransform.
    */
   static void PostTranslate(Matrix4x4& aTransform, const nsPoint& aOrigin,
                             float aAppUnitsPerPixel, bool aRounded);
 
+  /*
+   * Whether the frame should snap to grid. This will end up being passed
+   * as the aRounded parameter in PostTranslate above. SVG frames should
+   * not have their translation rounded.
+   */
+  static bool ShouldSnapToGrid(const nsIFrame* aFrame);
+
   /**
    * Get the border-box of aElement's primary frame, transformed it to be
    * relative to aFrame.
    */
   static nsRect GetRectRelativeToFrame(mozilla::dom::Element* aElement,
                                        nsIFrame* aFrame);
 
   /**
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -4895,23 +4895,17 @@ void ContainerState::ProcessDisplayItems
 
       if (!ownLayer) {
         continue;
       }
 
       NS_ASSERTION(!ownLayer->AsPaintedLayer(),
                    "Should never have created a dedicated Painted layer!");
 
-      if (item->BackfaceIsHidden()) {
-        ownLayer->SetContentFlags(ownLayer->GetContentFlags() |
-                                  Layer::CONTENT_BACKFACE_HIDDEN);
-      } else {
-        ownLayer->SetContentFlags(ownLayer->GetContentFlags() &
-                                  ~Layer::CONTENT_BACKFACE_HIDDEN);
-      }
+      SetBackfaceHiddenForLayer(item->BackfaceIsHidden(), ownLayer);
 
       nsRect invalid;
       if (item->IsInvalid(invalid)) {
         ownLayer->SetInvalidRectToVisibleRegion();
       }
 
       // If it's not a ContainerLayer, we need to apply the scale transform
       // ourselves.
@@ -6328,16 +6322,19 @@ already_AddRefed<ContainerLayer> FrameLa
   if (aChildren->IsOpaque() && !aChildren->NeedsTransparentSurface()) {
     bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
     if (bounds.Contains(ToAppUnits(pixBounds, appUnitsPerDevPixel))) {
       // Clear CONTENT_COMPONENT_ALPHA and add CONTENT_OPAQUE instead.
       flags &= ~Layer::CONTENT_COMPONENT_ALPHA;
       flags |= Layer::CONTENT_OPAQUE;
     }
   }
+  if (nsLayoutUtils::ShouldSnapToGrid(aContainerFrame)) {
+    flags |= Layer::CONTENT_SNAP_TO_GRID;
+  }
   containerLayer->SetContentFlags(flags);
   // If aContainerItem is non-null some BuildContainerLayer further up the
   // call stack is responsible for setting containerLayer's visible region.
   if (!aContainerItem) {
     containerLayer->SetVisibleRegion(
         LayerIntRegion::FromUnknownRegion(pixBounds));
   }
   if (aParameters.mLayerContentsVisibleRect) {
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -7574,24 +7574,16 @@ Matrix4x4 nsDisplayTransform::GetResulti
     const nsIFrame* aFrame, const nsPoint& aOrigin, float aAppUnitsPerPixel,
     uint32_t aFlags) {
   TransformReferenceBox refBox(aFrame);
   FrameTransformProperties props(aFrame, refBox, aAppUnitsPerPixel);
   return GetResultingTransformMatrixInternal(props, refBox, aOrigin,
                                              aAppUnitsPerPixel, aFlags);
 }
 
-static bool ShouldRoundTransformOrigin(const nsIFrame* aFrame) {
-  // An SVG frame should not have its translation rounded.
-  // Note it's possible that the SVG frame doesn't have an SVG
-  // transform but only has a CSS transform.
-  return !aFrame || !aFrame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) ||
-         aFrame->IsSVGOuterSVGAnonChildFrame();
-}
-
 Matrix4x4 nsDisplayTransform::GetResultingTransformMatrixInternal(
     const FrameTransformProperties& aProperties, TransformReferenceBox& aRefBox,
     const nsPoint& aOrigin, float aAppUnitsPerPixel, uint32_t aFlags) {
   const nsIFrame* frame = aProperties.mFrame;
   NS_ASSERTION(frame || !(aFlags & INCLUDE_PERSPECTIVE),
                "Must have a frame to compute perspective!");
 
   // Get the underlying transform matrix:
@@ -7601,17 +7593,17 @@ Matrix4x4 nsDisplayTransform::GetResulti
   // Call IsSVGTransformed() regardless of the value of
   // disp->mSpecifiedTransform, since we still need any
   // parentsChildrenOnlyTransform.
   Matrix svgTransform, parentsChildrenOnlyTransform;
   bool hasSVGTransforms =
       frame &&
       frame->IsSVGTransformed(&svgTransform, &parentsChildrenOnlyTransform);
 
-  bool shouldRound = ShouldRoundTransformOrigin(frame);
+  bool shouldRound = nsLayoutUtils::ShouldSnapToGrid(frame);
 
   /* Transformed frames always have a transform, or are preserving 3d (and might
    * still have perspective!) */
   if (aProperties.HasTransform()) {
     result = nsStyleTransformMatrix::ReadTransforms(
         aProperties.mTranslate, aProperties.mRotate, aProperties.mScale,
         aProperties.mMotion, aProperties.mTransform, aRefBox,
         aAppUnitsPerPixel);
@@ -7920,17 +7912,17 @@ Matrix4x4 nsDisplayTransform::GetTransfo
       // If aOutOrigin is provided, put the offset to origin into it, because
       // we need to keep it separate for webrender. The combination of
       // *aOutOrigin and the returned matrix here should always be equivalent
       // to what GetTransform() would have returned.
       float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
       *aOutOrigin = LayoutDevicePoint::FromAppUnits(ToReferenceFrame(), scale);
 
       // The rounding behavior should also be the same as GetTransform().
-      if (ShouldRoundTransformOrigin(mFrame)) {
+      if (nsLayoutUtils::ShouldSnapToGrid(mFrame)) {
         aOutOrigin->Round();
       }
       return GetResultingTransformMatrix(mFrame, nsPoint(0, 0), scale,
                                          INCLUDE_PERSPECTIVE);
     }
     return GetTransform().GetMatrix();
   }
   MOZ_ASSERT(!mTransformGetter);