Bug 1732600. Pass down transform to ancestor scale to child processes. r=botond
authorTimothy Nikkel <tnikkel@gmail.com>
Tue, 05 Oct 2021 09:28:57 +0000
changeset 594592 ea1f49e03b8b019c2b12be64c90636af4602773a
parent 594591 fcba9b3345131a80dd5ef7e3299250bf34b6d355
child 594593 d39165de0a11e4a26c5b6c61b5765ae9129730f1
push id150878
push usertnikkel@mozilla.com
push dateTue, 05 Oct 2021 09:31:46 +0000
treeherderautoland@9e95cc6419d7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1732600, 1731929
milestone95.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 1732600. Pass down transform to ancestor scale to child processes. r=botond In bug 1731929 we added this value, here we give it the value we want for child processes. I think the code comments should explain it. Differential Revision: https://phabricator.services.mozilla.com/D126629
dom/ipc/EffectsInfo.h
dom/ipc/TabMessageUtils.h
gfx/layers/FrameMetrics.h
gfx/layers/RepaintRequest.h
layout/base/UnitTransforms.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsSubDocumentFrame.cpp
--- a/dom/ipc/EffectsInfo.h
+++ b/dom/ipc/EffectsInfo.h
@@ -16,40 +16,61 @@ namespace dom {
  * An EffectsInfo contains information for a remote browser about the graphical
  * effects that are being applied to it by ancestor browsers in different
  * processes.
  */
 class EffectsInfo {
  public:
   EffectsInfo() { *this = EffectsInfo::FullyHidden(); }
 
-  static EffectsInfo VisibleWithinRect(const nsRect& aVisibleRect,
-                                       float aScaleX, float aScaleY) {
-    return EffectsInfo{aVisibleRect, aScaleX, aScaleY};
+  static EffectsInfo VisibleWithinRect(
+      const nsRect& aVisibleRect, float aScaleX, float aScaleY,
+      const ParentLayerToScreenScale2D& aTransformToAncestorScale) {
+    return EffectsInfo{aVisibleRect, aScaleX, aScaleY,
+                       aTransformToAncestorScale};
   }
-  static EffectsInfo FullyHidden() { return EffectsInfo{nsRect(), 1.0f, 1.0f}; }
+  static EffectsInfo FullyHidden() {
+    return EffectsInfo{nsRect(), 1.0f, 1.0f, ParentLayerToScreenScale2D()};
+  }
 
   bool operator==(const EffectsInfo& aOther) {
     return mVisibleRect == aOther.mVisibleRect && mScaleX == aOther.mScaleX &&
-           mScaleY == aOther.mScaleY;
+           mScaleY == aOther.mScaleY &&
+           mTransformToAncestorScale == aOther.mTransformToAncestorScale;
   }
   bool operator!=(const EffectsInfo& aOther) { return !(*this == aOther); }
 
   bool IsVisible() const { return !mVisibleRect.IsEmpty(); }
 
   // The visible rect of this browser relative to the root frame. If this is
   // empty then the browser can be considered invisible.
   nsRect mVisibleRect;
   // The desired scale factors to apply to rasterized content to match
-  // transforms applied in ancestor browsers.
+  // transforms applied in ancestor browsers. This gets propagated into the
+  // scale in StackingContextHelper.
   float mScaleX;
   float mScaleY;
-  // If you add new fields here, you must also update operator==
+  // TransformToAncestorScale to be set on FrameMetrics. It includes CSS
+  // transform scales and cumulative presshell resolution.
+  ParentLayerToScreenScale2D mTransformToAncestorScale;
+  // The difference between mScaleX/Y and mTransformToAncestorScale is the way
+  // that CSS transforms contribute to the scale. mTransformToAncestorScale
+  // includes the exact scale factors of the combined CSS transform whereas
+  // mScaleX/Y tries to take into account animating transform scales by picking
+  // a larger scale so that we don't have to re-rasterize every frame but rather
+  // we can just scale down  content rasterized on a previous frame.
+
+  // If you add new fields here, you must also update operator== and
+  // TabMessageUtils.
 
  private:
-  EffectsInfo(const nsRect& aVisibleRect, float aScaleX, float aScaleY)
-      : mVisibleRect(aVisibleRect), mScaleX(aScaleX), mScaleY(aScaleY) {}
+  EffectsInfo(const nsRect& aVisibleRect, float aScaleX, float aScaleY,
+              const ParentLayerToScreenScale2D& aTransformToAncestorScale)
+      : mVisibleRect(aVisibleRect),
+        mScaleX(aScaleX),
+        mScaleY(aScaleY),
+        mTransformToAncestorScale(aTransformToAncestorScale) {}
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_EffectsInfo_h
--- a/dom/ipc/TabMessageUtils.h
+++ b/dom/ipc/TabMessageUtils.h
@@ -64,23 +64,25 @@ struct ParamTraits<nsIRemoteTab::Navigat
 template <>
 struct ParamTraits<mozilla::dom::EffectsInfo> {
   typedef mozilla::dom::EffectsInfo paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mVisibleRect);
     WriteParam(aMsg, aParam.mScaleX);
     WriteParam(aMsg, aParam.mScaleY);
+    WriteParam(aMsg, aParam.mTransformToAncestorScale);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    paramType* aResult) {
     return ReadParam(aMsg, aIter, &aResult->mVisibleRect) &&
            ReadParam(aMsg, aIter, &aResult->mScaleX) &&
-           ReadParam(aMsg, aIter, &aResult->mScaleY);
+           ReadParam(aMsg, aIter, &aResult->mScaleY) &&
+           ReadParam(aMsg, aIter, &aResult->mTransformToAncestorScale);
   }
 };
 
 template <>
 struct ParamTraits<mozilla::WhenToScroll>
     : public ContiguousEnumSerializerInclusive<
           mozilla::WhenToScroll, mozilla::WhenToScroll::Always,
           mozilla::WhenToScroll::IfNotFullyVisible> {};
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -637,17 +637,24 @@ struct FrameMetrics {
   // Note that only the root content document's RSF has a layout viewport
   // that's distinct from the visual viewport. For an iframe RSF, the two
   // are the same.
   //
   // For a scroll frame that is not an RSF, this metric is meaningless and
   // invalid.
   CSSRect mLayoutViewport;
 
-  // The scale on this scroll frame induced by enclosing CSS transforms.
+  // The scale induced by css transforms and presshell resolution in this
+  // process and any ancestor processes that encloses this scroll frame that is
+  // _not_ included in mCumulativeResolution. This means that in the process of
+  // the root content document this only includes css transform scale (which
+  // happens in that process, but we assume there can be no css transform scale
+  // above the root content document). In other processes it includes css
+  // transform scale and any resolution scale in the current process and all
+  // ancestor processes.
   ParentLayerToScreenScale2D mTransformToAncestorScale;
 
   // The time at which the APZC last requested a repaint for this scroll frame.
   TimeStamp mPaintRequestTime;
 
   // These fields are used when the main thread wants to set a visual viewport
   // offset that's distinct from the layout viewport offset.
   // In this case, mVisualScrollUpdateType is set to eMainThread, and
--- a/gfx/layers/RepaintRequest.h
+++ b/gfx/layers/RepaintRequest.h
@@ -267,17 +267,17 @@ struct RepaintRequest {
   // Note that only the root content document's RSF has a layout viewport
   // that's distinct from the visual viewport. For an iframe RSF, the two
   // are the same.
   //
   // For a scroll frame that is not an RSF, this metric is meaningless and
   // invalid.
   CSSRect mLayoutViewport;
 
-  // The scale on this scroll frame induced by enclosing CSS transforms.
+  // See FrameMetrics::mTransformToAncestorScale for description.
   ParentLayerToScreenScale2D mTransformToAncestorScale;
 
   // The time at which the APZC last requested a repaint for this scroll frame.
   TimeStamp mPaintRequestTime;
 
   // The type of repaint request this represents.
   ScrollOffsetUpdateType mScrollUpdateType;
 
--- a/layout/base/UnitTransforms.h
+++ b/layout/base/UnitTransforms.h
@@ -61,16 +61,18 @@ enum class PixelCastJustification : uint
   LayerIsImage,
   // External pixels are the same scale as screen pixels
   ExternalIsScreen,
   // LayerToScreenMatrix is used as LayoutDeviceToLayoutDevice, because
   // out-of-process iframes uses LayoutDevicePixels as the type system-visible
   // type of their top-level event coordinate space even if technically
   // inaccurate.
   ContentProcessIsLayerInUiProcess,
+  // Propagating TransformToAncestorScale to a child process.
+  PropagatingToChildProcess,
 };
 
 template <class TargetUnits, class SourceUnits>
 gfx::CoordTyped<TargetUnits> ViewAs(const gfx::CoordTyped<SourceUnits>& aCoord,
                                     PixelCastJustification) {
   return gfx::CoordTyped<TargetUnits>(aCoord.value);
 }
 template <class TargetUnits, class SourceUnits>
@@ -129,16 +131,23 @@ gfx::IntRegionTyped<TargetUnits> ViewAs(
       aRegion.ToUnknownRegion());
 }
 template <class NewTargetUnits, class OldTargetUnits, class SourceUnits>
 gfx::ScaleFactor<SourceUnits, NewTargetUnits> ViewTargetAs(
     const gfx::ScaleFactor<SourceUnits, OldTargetUnits>& aScaleFactor,
     PixelCastJustification) {
   return gfx::ScaleFactor<SourceUnits, NewTargetUnits>(aScaleFactor.scale);
 }
+template <class NewTargetUnits, class OldTargetUnits, class SourceUnits>
+gfx::ScaleFactors2D<SourceUnits, NewTargetUnits> ViewTargetAs(
+    const gfx::ScaleFactors2D<SourceUnits, OldTargetUnits>& aScaleFactors,
+    PixelCastJustification) {
+  return gfx::ScaleFactors2D<SourceUnits, NewTargetUnits>(aScaleFactors.xScale,
+                                                          aScaleFactors.yScale);
+}
 template <class TargetUnits, class SourceUnits>
 Maybe<gfx::IntRectTyped<TargetUnits>> ViewAs(
     const Maybe<gfx::IntRectTyped<SourceUnits>>& aRect,
     PixelCastJustification aJustification) {
   if (aRect.isSome()) {
     return Some(ViewAs<TargetUnits>(aRect.value(), aJustification));
   }
   return Nothing();
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2773,16 +2773,33 @@ nsresult nsLayoutUtils::GetFramesForArea
 
   nsDisplayItem::HitTestState hitTestState;
   list.HitTest(&builder, aRect, &hitTestState, &aOutFrames);
   list.DeleteAll(&builder);
   builder.EndFrame();
   return NS_OK;
 }
 
+mozilla::ParentLayerToScreenScale2D
+nsLayoutUtils::GetTransformToAncestorScaleCrossProcessForFrameMetrics(
+    const nsIFrame* aFrame) {
+  ParentLayerToScreenScale2D transformToAncestorScale(
+      nsLayoutUtils::GetTransformToAncestorScale(aFrame));
+
+  if (BrowserChild* browserChild = BrowserChild::GetFrom(aFrame->PresShell())) {
+    transformToAncestorScale =
+        ViewTargetAs<ParentLayerPixel>(
+            transformToAncestorScale,
+            PixelCastJustification::PropagatingToChildProcess) *
+        browserChild->GetEffectsInfo().mTransformToAncestorScale;
+  }
+
+  return transformToAncestorScale;
+}
+
 // aScrollFrameAsScrollable must be non-nullptr and queryable to an nsIFrame
 FrameMetrics nsLayoutUtils::CalculateBasicFrameMetrics(
     nsIScrollableFrame* aScrollFrame) {
   nsIFrame* frame = do_QueryFrame(aScrollFrame);
   MOZ_ASSERT(frame);
 
   // Calculate the metrics necessary for calculating the displayport.
   // This code has a lot in common with the code in ComputeFrameMetrics();
@@ -2801,18 +2818,19 @@ FrameMetrics nsLayoutUtils::CalculateBas
     resolution = presShell->GetResolution();
   }
   LayoutDeviceToLayerScale2D cumulativeResolution(
       LayoutDeviceToLayerScale(presShell->GetCumulativeResolution()));
 
   LayerToParentLayerScale layerToParentLayerScale(1.0f);
   metrics.SetDevPixelsPerCSSPixel(deviceScale);
   metrics.SetPresShellResolution(resolution);
-  metrics.SetTransformToAncestorScale(ParentLayerToScreenScale2D(
-      nsLayoutUtils::GetTransformToAncestorScale(frame)));
+
+  metrics.SetTransformToAncestorScale(
+      GetTransformToAncestorScaleCrossProcessForFrameMetrics(frame));
   metrics.SetCumulativeResolution(cumulativeResolution);
   metrics.SetZoom(deviceScale * cumulativeResolution * layerToParentLayerScale);
 
   // Only the size of the composition bounds is relevant to the
   // displayport calculation, not its origin.
   nsSize compositionSize =
       nsLayoutUtils::CalculateCompositionSizeForFrame(frame);
   LayoutDeviceToParentLayerScale2D compBoundsScale;
@@ -8760,22 +8778,19 @@ ScrollMetadata nsLayoutUtils::ComputeScr
   // resolution. We don't need to compute it as it's already stored in the
   // container parameters... except if we're in WebRender in which case we
   // don't have a aContainerParameters. In that case we're also not rasterizing
   // in Gecko anyway, so the only resolution we care about here is the presShell
   // resolution which we need to propagate to WebRender.
   metrics.SetCumulativeResolution(LayoutDeviceToLayerScale2D(
       LayoutDeviceToLayerScale(presShell->GetCumulativeResolution())));
 
-  gfxSize transformToAncestorScale = nsLayoutUtils::GetTransformToAncestorScale(
-      aScrollFrame ? aScrollFrame : aForFrame);
-
   metrics.SetTransformToAncestorScale(
-      ParentLayerToScreenScale2D(transformToAncestorScale));
-
+      GetTransformToAncestorScaleCrossProcessForFrameMetrics(
+          aScrollFrame ? aScrollFrame : aForFrame));
   metrics.SetDevPixelsPerCSSPixel(presContext->CSSToDevPixelScale());
 
   // Initially, AsyncPanZoomController should render the content to the screen
   // at the painted resolution.
   const LayerToParentLayerScale layerToParentLayerScale(1.0f);
   metrics.SetZoom(metrics.GetCumulativeResolution() *
                   metrics.GetDevPixelsPerCSSPixel() * layerToParentLayerScale);
 
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -940,16 +940,29 @@ class nsLayoutUtils {
    * Gets the scale factors of the transform for aFrame relative to the root
    * frame if this transform is 2D, or the identity scale factors otherwise.
    * If some frame on the path from aFrame to the display root frame may have an
    * animated scale, returns the identity scale factors.
    */
   static gfxSize GetTransformToAncestorScaleExcludingAnimated(nsIFrame* aFrame);
 
   /**
+   * Gets a scale that includes CSS transforms in this process as well as the
+   * transform to ancestor scale passed down from our direct ancestor process
+   * (which includes any enclosing CSS transforms and resolution). Note: this
+   * does not include any resolution in the current process (this is on purpose
+   * because that is what the transform to ancestor field on FrameMetrics needs,
+   * see its definition for explanation as to why). This is the transform to
+   * ancestor scale to set on FrameMetrics.
+   */
+  static mozilla::ParentLayerToScreenScale2D
+  GetTransformToAncestorScaleCrossProcessForFrameMetrics(
+      const nsIFrame* aFrame);
+
+  /**
    * Find the nearest common ancestor frame for aFrame1 and aFrame2. The
    * ancestor frame could be cross-doc.
    */
   static const nsIFrame* FindNearestCommonAncestorFrame(
       const nsIFrame* aFrame1, const nsIFrame* aFrame2);
 
   /**
    * Find the nearest common ancestor frame for aFrame1 and aFrame2, assuming
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -1347,19 +1347,28 @@ bool nsDisplayRemote::CreateWebRenderCom
     // relative to this frame
     nsRect visibleRect = GetBuildingRect() - ToReferenceFrame();
     nsRect contentRect = Frame()->GetContentRectRelativeToSelf();
     visibleRect.IntersectRect(visibleRect, contentRect);
     visibleRect -= contentRect.TopLeft();
 
     // Generate an effects update notifying the browser it is visible
     gfx::Size scale = aSc.GetInheritedScale();
+
+    ParentLayerToScreenScale2D transformToAncestorScale =
+        ParentLayerToParentLayerScale(
+            pc->GetPresShell() ? pc->GetPresShell()->GetCumulativeResolution()
+                               : 1.f) *
+        nsLayoutUtils::GetTransformToAncestorScaleCrossProcessForFrameMetrics(
+            mFrame);
+
     aDisplayListBuilder->AddEffectUpdate(
         remoteBrowser,
-        EffectsInfo::VisibleWithinRect(visibleRect, scale.width, scale.height));
+        EffectsInfo::VisibleWithinRect(visibleRect, scale.width, scale.height,
+                                       transformToAncestorScale));
 
     // Create a WebRenderRemoteData to notify the RemoteBrowser when it is no
     // longer visible
     RefPtr<WebRenderRemoteData> userData =
         aManager->CommandBuilder()
             .CreateOrRecycleWebRenderUserData<WebRenderRemoteData>(this,
                                                                    nullptr);
     userData->SetRemoteBrowser(remoteBrowser);