Bug 1324591 - Inform the partial prerender rect and the overflowed SideBits to the compositor. r?botond draft
authorHiroyuki Ikezoe <hikezoe.birchill@mozilla.com>
Mon, 18 May 2020 09:27:20 +0900
changeset 3000250 4411031d6244491ccf3515a543f0296d28f510ee
parent 3000249 b1593da16002b7d021c51c0c94cd5cd90cfd38d4
child 3000251 9deb1a97e28eb09c4f7296162309a362bfd9c1b6
child 3000353 58f5942f2a4fae6bbeb5edf234332cd879fb6b03
push id558657
push userhikezoe.birchill@mozilla.com
push dateWed, 24 Jun 2020 01:19:11 +0000
treeherdertry@bb059ebb3e19 [default view] [failures only]
reviewersbotond
bugs1324591
milestone79.0a1
Bug 1324591 - Inform the partial prerender rect and the overflowed SideBits to the compositor. r?botond nsDisplayTransform doesn't have enough room to store the partial prerender rect and the overflowed SideBits unfortunately (it will exceed 512 bytes limit [1]). So we get the partial prerender rect and calculate the overflowed SideBits just before we send transform animation information to the compositor. [1] https://searchfox.org/mozilla-central/rev/fa52bedc4b401c12251513fa1c9df1753a29abb2/layout/painting/nsDisplayList.cpp#7318 Differential Revision: https://phabricator.services.mozilla.com/D75730
gfx/layers/AnimationInfo.cpp
gfx/layers/ipc/LayersMessages.ipdlh
layout/painting/nsDisplayList.h
--- a/gfx/layers/AnimationInfo.cpp
+++ b/gfx/layers/AnimationInfo.cpp
@@ -642,16 +642,40 @@ bool AnimationInfo::AddAnimationsForProp
 
     AddAnimationForProperty(aFrame, *property, anim, aTransformData, aSendFlag);
     keyframeEffect->SetIsRunningOnCompositor(aProperty, true);
     addedAny = true;
   }
   return addedAny;
 }
 
+// Returns which pre-rendered area's sides are overflowed from the pre-rendered
+// rect.
+//
+// We don't need to make jank animations when we are going to composite the
+// area where there is no overflowed area even if it's outside of the
+// pre-rendered area.
+static SideBits GetOverflowedSides(const nsRect& aOverflow,
+                                   const nsRect& aPartialPrerenderArea) {
+  SideBits sides = SideBits::eNone;
+  if (aOverflow.X() < aPartialPrerenderArea.X()) {
+    sides |= SideBits::eLeft;
+  }
+  if (aOverflow.Y() < aPartialPrerenderArea.Y()) {
+    sides |= SideBits::eTop;
+  }
+  if (aOverflow.XMost() > aPartialPrerenderArea.XMost()) {
+    sides |= SideBits::eRight;
+  }
+  if (aOverflow.YMost() > aPartialPrerenderArea.YMost()) {
+    sides |= SideBits::eBottom;
+  }
+  return sides;
+}
+
 enum class AnimationDataType {
   WithMotionPath,
   WithoutMotionPath,
 };
 static Maybe<TransformData> CreateAnimationData(
     nsIFrame* aFrame, nsDisplayItem* aItem, DisplayItemType aType,
     layers::LayersBackend aLayersBackend, AnimationDataType aDataType) {
   if (aType != DisplayItemType::TYPE_TRANSFORM) {
@@ -702,19 +726,29 @@ static Maybe<TransformData> CreateAnimat
         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));
+  Maybe<PartialPrerenderData> partialPrerenderData;
+  if (aItem && static_cast<nsDisplayTransform*>(aItem)->IsPartialPrerender()) {
+    const nsRect& partialPrerenderedRect = aItem->GetUntransformedPaintRect();
+    nsRect overflow = aFrame->GetVisualOverflowRectRelativeToSelf();
+    partialPrerenderData = Some(PartialPrerenderData{
+        LayoutDeviceIntRect::FromAppUnitsToInside(partialPrerenderedRect,
+                                                  devPixelsToAppUnits),
+        GetOverflowedSides(overflow, partialPrerenderedRect)});
+  }
+
+  return Some(TransformData(
+      origin, offsetToTransformOrigin, bounds, devPixelsToAppUnits, scaleX,
+      scaleY, hasPerspectiveParent, motionPathData, partialPrerenderData));
 }
 
 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/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -15,16 +15,17 @@ include "ImageLayers.h";
 
 using mozilla::gfx::Glyph from "mozilla/gfx/2D.h";
 using mozilla::gfx::SamplingFilter from "mozilla/gfx/2D.h";
 using struct mozilla::gfx::DeviceColor from "mozilla/gfx/2D.h";
 using struct mozilla::gfx::Point from "mozilla/gfx/Point.h";
 using struct mozilla::gfx::Point3D from "mozilla/gfx/Point.h";
 using mozilla::gfx::IntPoint from "mozilla/gfx/Point.h";
 using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
+using class mozilla::SideBits from "mozilla/gfx/Types.h";
 using nscolor from "nsColor.h";
 using nscoord from "nsCoord.h";
 using struct nsRect from "nsRect.h";
 using struct nsPoint from "nsPoint.h";
 using class mozilla::TimeDuration from "mozilla/TimeStamp.h";
 using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using mozilla::ScreenRotation from "mozilla/WidgetUtils.h";
 using nsCSSPropertyID from "nsCSSPropertyID.h";
@@ -33,16 +34,17 @@ using struct mozilla::layers::TextureInf
 using mozilla::CSSPoint from "Units.h";
 using mozilla::CSSRect from "Units.h";
 using mozilla::LayerMargin from "Units.h";
 using mozilla::LayerPoint from "Units.h";
 using mozilla::LayerCoord from "Units.h";
 using mozilla::LayerSize from "Units.h";
 using mozilla::LayerRect from "Units.h";
 using mozilla::LayerIntSize from "Units.h";
+using mozilla::LayerIntRect from "Units.h";
 using mozilla::LayerIntRegion from "Units.h";
 using mozilla::ParentLayerIntRect from "Units.h";
 using mozilla::LayoutDeviceIntRect from "Units.h";
 using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegionsOverride from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
 using mozilla::layers::FocusTarget from "mozilla/layers/FocusTarget.h";
@@ -148,31 +150,37 @@ struct AnimationSegment {
 struct MotionPathData {
   // the transform-origin property for motion in css pixels
   CSSPoint origin;
   // the adjustment for the anchor point of motion path.
   CSSPoint anchorAdjustment;
   RayReferenceData rayReferenceData;
 };
 
+struct PartialPrerenderData {
+  LayoutDeviceIntRect rect;
+  SideBits overflowedSides;
+};
+
 // Transforms need extra information to correctly convert the list of transform
 // functions to a Matrix4x4 that can be applied directly to the layer.
 struct TransformData {
   // the origin of the frame being transformed in app units
   nsPoint origin;
   // the transform-origin property for the transform in device pixels
   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;
   MotionPathData? motionPathData;
+  PartialPrerenderData? partialPrerenderData;
 };
 
 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
   // start times in the distant past that cannot be expressed using a TimeStamp.
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -7039,16 +7039,20 @@ class nsDisplayTransform : public nsDisp
   /**
    * The backing frame of this item participates a 3D rendering
    * context.
    */
   bool IsParticipating3DContext() const {
     return mFrame->Extend3DContext() || Combines3DTransformWithAncestors();
   }
 
+  bool IsPartialPrerender() const {
+    return mPrerenderDecision == PrerenderDecision::Partial;
+  }
+
   void AddSizeOfExcludingThis(nsWindowSizes&) const override;
 
  private:
   void ComputeBounds(nsDisplayListBuilder* aBuilder);
   nsRect TransformUntransformedBounds(nsDisplayListBuilder* aBuilder,
                                       const Matrix4x4Flagged& aMatrix) const;
   void UpdateUntransformedBounds(nsDisplayListBuilder* aBuilder);