LCOV - code coverage report
Current view: top level - gfx/layers/composite - AsyncCompositionManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 229 548 41.8 %
Date: 2017-07-14 16:53:18 Functions: 21 42 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set sw=2 ts=2 et tw=80 : */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/layers/AsyncCompositionManager.h"
       8             : #include <stdint.h>                     // for uint32_t
       9             : #include "apz/src/AsyncPanZoomController.h"
      10             : #include "FrameMetrics.h"               // for FrameMetrics
      11             : #include "LayerManagerComposite.h"      // for LayerManagerComposite, etc
      12             : #include "Layers.h"                     // for Layer, ContainerLayer, etc
      13             : #include "gfxPoint.h"                   // for gfxPoint, gfxSize
      14             : #include "gfxPrefs.h"                   // for gfxPrefs
      15             : #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
      16             : #include "mozilla/WidgetUtils.h"        // for ComputeTransformForRotation
      17             : #include "mozilla/gfx/BaseRect.h"       // for BaseRect
      18             : #include "mozilla/gfx/Point.h"          // for RoundedToInt, PointTyped
      19             : #include "mozilla/gfx/Rect.h"           // for RoundedToInt, RectTyped
      20             : #include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
      21             : #include "mozilla/layers/AnimationHelper.h"
      22             : #include "mozilla/layers/APZUtils.h"    // for CompleteAsyncTransform
      23             : #include "mozilla/layers/Compositor.h"  // for Compositor
      24             : #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent, etc
      25             : #include "mozilla/layers/CompositorThread.h"
      26             : #include "mozilla/layers/LayerAnimationUtils.h" // for TimingFunctionToComputedTimingFunction
      27             : #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
      28             : #include "nsCoord.h"                    // for NSAppUnitsToFloatPixels, etc
      29             : #include "nsDebug.h"                    // for NS_ASSERTION, etc
      30             : #include "nsDeviceContext.h"            // for nsDeviceContext
      31             : #include "nsDisplayList.h"              // for nsDisplayTransform, etc
      32             : #include "nsMathUtils.h"                // for NS_round
      33             : #include "nsPoint.h"                    // for nsPoint
      34             : #include "nsRect.h"                     // for mozilla::gfx::IntRect
      35             : #include "nsRegion.h"                   // for nsIntRegion
      36             : #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
      37             : #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
      38             : #include "UnitTransforms.h"             // for TransformTo
      39             : #include "gfxPrefs.h"
      40             : #if defined(MOZ_WIDGET_ANDROID)
      41             : # include <android/log.h>
      42             : # include "mozilla/layers/UiCompositorControllerParent.h"
      43             : # include "mozilla/widget/AndroidCompositorWidget.h"
      44             : #endif
      45             : #include "GeckoProfiler.h"
      46             : #include "FrameUniformityData.h"
      47             : #include "TreeTraversal.h"              // for ForEachNode, BreadthFirstSearch
      48             : #include "VsyncSource.h"
      49             : 
      50             : struct nsCSSValueSharedList;
      51             : 
      52             : namespace mozilla {
      53             : namespace layers {
      54             : 
      55             : using namespace mozilla::gfx;
      56             : 
      57             : static bool
      58         104 : IsSameDimension(dom::ScreenOrientationInternal o1, dom::ScreenOrientationInternal o2)
      59             : {
      60         104 :   bool isO1portrait = (o1 == dom::eScreenOrientation_PortraitPrimary || o1 == dom::eScreenOrientation_PortraitSecondary);
      61         104 :   bool isO2portrait = (o2 == dom::eScreenOrientation_PortraitPrimary || o2 == dom::eScreenOrientation_PortraitSecondary);
      62         104 :   return !(isO1portrait ^ isO2portrait);
      63             : }
      64             : 
      65             : static bool
      66           0 : ContentMightReflowOnOrientationChange(const IntRect& rect)
      67             : {
      68           0 :   return rect.width != rect.height;
      69             : }
      70             : 
      71           1 :   AsyncCompositionManager::AsyncCompositionManager(CompositorBridgeParent* aParent,
      72           1 :                                                    HostLayerManager* aManager)
      73             :   : mLayerManager(aManager)
      74             :   , mIsFirstPaint(true)
      75             :   , mLayersUpdated(false)
      76             :   , mReadyForCompose(true)
      77           1 :   , mCompositorBridge(aParent)
      78             : {
      79           1 : }
      80             : 
      81           0 : AsyncCompositionManager::~AsyncCompositionManager()
      82             : {
      83           0 : }
      84             : 
      85             : void
      86         113 : AsyncCompositionManager::ResolveRefLayers(CompositorBridgeParent* aCompositor,
      87             :                                           bool* aHasRemoteContent,
      88             :                                           bool* aResolvePlugins)
      89             : {
      90         113 :   if (aHasRemoteContent) {
      91          29 :     *aHasRemoteContent = false;
      92             :   }
      93             : 
      94             : #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
      95             :   // If valid *aResolvePlugins indicates if we need to update plugin geometry
      96             :   // when we walk the tree.
      97         113 :   bool resolvePlugins = (aCompositor && aResolvePlugins && *aResolvePlugins);
      98             : #endif
      99             : 
     100         113 :   if (!mLayerManager->GetRoot()) {
     101             :     // Updated the return value since this result controls completing composition.
     102           1 :     if (aResolvePlugins) {
     103           0 :       *aResolvePlugins = false;
     104             :     }
     105           1 :     return;
     106             :   }
     107             : 
     108         112 :   mReadyForCompose = true;
     109         112 :   bool hasRemoteContent = false;
     110         112 :   bool didResolvePlugins = false;
     111             : 
     112         336 :   ForEachNode<ForwardIterator>(
     113         112 :     mLayerManager->GetRoot(),
     114         841 :     [&](Layer* layer)
     115             :     {
     116         841 :       RefLayer* refLayer = layer->AsRefLayer();
     117         841 :       if (!refLayer) {
     118         729 :         return;
     119             :       }
     120             : 
     121         112 :       hasRemoteContent = true;
     122             :       const CompositorBridgeParent::LayerTreeState* state =
     123         112 :         CompositorBridgeParent::GetIndirectShadowTree(refLayer->GetReferentId());
     124         112 :       if (!state) {
     125           0 :         return;
     126             :       }
     127             : 
     128         112 :       Layer* referent = state->mRoot;
     129         112 :       if (!referent) {
     130           8 :         return;
     131             :       }
     132             : 
     133         104 :       if (!refLayer->GetLocalVisibleRegion().IsEmpty()) {
     134             :         dom::ScreenOrientationInternal chromeOrientation =
     135         104 :           mTargetConfig.orientation();
     136             :         dom::ScreenOrientationInternal contentOrientation =
     137         104 :           state->mTargetConfig.orientation();
     138         104 :         if (!IsSameDimension(chromeOrientation, contentOrientation) &&
     139           0 :             ContentMightReflowOnOrientationChange(mTargetConfig.naturalBounds())) {
     140           0 :           mReadyForCompose = false;
     141             :         }
     142             :       }
     143             : 
     144         104 :       refLayer->ConnectReferentLayer(referent);
     145             : 
     146             : #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
     147         104 :       if (resolvePlugins) {
     148          62 :         didResolvePlugins |=
     149          62 :           aCompositor->UpdatePluginWindowState(refLayer->GetReferentId());
     150             :       }
     151             : #endif
     152         112 :     });
     153             : 
     154         112 :   if (aHasRemoteContent) {
     155          29 :     *aHasRemoteContent = hasRemoteContent;
     156             :   }
     157         112 :   if (aResolvePlugins) {
     158          33 :     *aResolvePlugins = didResolvePlugins;
     159             :   }
     160             : }
     161             : 
     162             : void
     163         113 : AsyncCompositionManager::DetachRefLayers()
     164             : {
     165         113 :   if (!mLayerManager->GetRoot()) {
     166           1 :     return;
     167             :   }
     168             : 
     169         112 :   mReadyForCompose = false;
     170             : 
     171         224 :   ForEachNodePostOrder<ForwardIterator>(mLayerManager->GetRoot(),
     172         841 :     [&](Layer* layer)
     173             :     {
     174         841 :       RefLayer* refLayer = layer->AsRefLayer();
     175         841 :       if (!refLayer) {
     176         729 :         return;
     177             :       }
     178             : 
     179             :       const CompositorBridgeParent::LayerTreeState* state =
     180         112 :         CompositorBridgeParent::GetIndirectShadowTree(refLayer->GetReferentId());
     181         112 :       if (!state) {
     182           0 :         return;
     183             :       }
     184             : 
     185         112 :       Layer* referent = state->mRoot;
     186         112 :       if (referent) {
     187         104 :         refLayer->DetachReferentLayer(referent);
     188             :       }
     189         112 :     });
     190             : }
     191             : 
     192             : void
     193          29 : AsyncCompositionManager::ComputeRotation()
     194             : {
     195          29 :   if (!mTargetConfig.naturalBounds().IsEmpty()) {
     196             :     mWorldTransform =
     197          29 :       ComputeTransformForRotation(mTargetConfig.naturalBounds(),
     198          58 :                                   mTargetConfig.rotation());
     199             :   }
     200          29 : }
     201             : 
     202             : #ifdef DEBUG
     203             : static void
     204           0 : GetBaseTransform(Layer* aLayer, Matrix4x4* aTransform)
     205             : {
     206             :   // Start with the animated transform if there is one
     207             :   *aTransform =
     208           0 :     (aLayer->AsHostLayer()->GetShadowTransformSetByAnimation()
     209           0 :         ? aLayer->GetLocalTransform()
     210           0 :         : aLayer->GetTransform());
     211           0 : }
     212             : #endif
     213             : 
     214             : static void
     215           0 : TransformClipRect(Layer* aLayer,
     216             :                   const ParentLayerToParentLayerMatrix4x4& aTransform)
     217             : {
     218           0 :   MOZ_ASSERT(aTransform.Is2D());
     219           0 :   const Maybe<ParentLayerIntRect>& clipRect = aLayer->AsHostLayer()->GetShadowClipRect();
     220           0 :   if (clipRect) {
     221           0 :     ParentLayerIntRect transformed = TransformBy(aTransform, *clipRect);
     222           0 :     aLayer->AsHostLayer()->SetShadowClipRect(Some(transformed));
     223             :   }
     224           0 : }
     225             : 
     226             : // Similar to TransformFixedClip(), but only transforms the fixed part of the
     227             : // clip.
     228             : static void
     229           0 : TransformFixedClip(Layer* aLayer,
     230             :                    const ParentLayerToParentLayerMatrix4x4& aTransform,
     231             :                    AsyncCompositionManager::ClipParts& aClipParts)
     232             : {
     233           0 :   MOZ_ASSERT(aTransform.Is2D());
     234           0 :   if (aClipParts.mFixedClip) {
     235           0 :     *aClipParts.mFixedClip = TransformBy(aTransform, *aClipParts.mFixedClip);
     236           0 :     aLayer->AsHostLayer()->SetShadowClipRect(aClipParts.Intersect());
     237             :   }
     238           0 : }
     239             : 
     240             : /**
     241             :  * Set the given transform as the shadow transform on the layer, assuming
     242             :  * that the given transform already has the pre- and post-scales applied.
     243             :  * That is, this function cancels out the pre- and post-scales from aTransform
     244             :  * before setting it as the shadow transform on the layer, so that when
     245             :  * the layer's effective transform is computed, the pre- and post-scales will
     246             :  * only be applied once.
     247             :  */
     248             : static void
     249          40 : SetShadowTransform(Layer* aLayer, LayerToParentLayerMatrix4x4 aTransform)
     250             : {
     251          40 :   if (ContainerLayer* c = aLayer->AsContainerLayer()) {
     252          29 :     aTransform.PreScale(1.0f / c->GetPreXScale(),
     253          29 :                         1.0f / c->GetPreYScale(),
     254          58 :                         1);
     255             :   }
     256          40 :   aTransform.PostScale(1.0f / aLayer->GetPostXScale(),
     257          40 :                        1.0f / aLayer->GetPostYScale(),
     258          80 :                        1);
     259          40 :   aLayer->AsHostLayer()->SetShadowBaseTransform(aTransform.ToUnknownMatrix());
     260          40 : }
     261             : 
     262             : static void
     263           0 : TranslateShadowLayer(Layer* aLayer,
     264             :                      const ParentLayerPoint& aTranslation,
     265             :                      bool aAdjustClipRect,
     266             :                      AsyncCompositionManager::ClipPartsCache* aClipPartsCache)
     267             : {
     268             :   // This layer might also be a scrollable layer and have an async transform.
     269             :   // To make sure we don't clobber that, we start with the shadow transform.
     270             :   // (i.e. GetLocalTransform() instead of GetTransform()).
     271             :   // Note that the shadow transform is reset on every frame of composition so
     272             :   // we don't have to worry about the adjustments compounding over successive
     273             :   // frames.
     274           0 :   LayerToParentLayerMatrix4x4 layerTransform = aLayer->GetLocalTransformTyped();
     275             : 
     276             :   // Apply the translation to the layer transform.
     277           0 :   layerTransform.PostTranslate(aTranslation);
     278             : 
     279           0 :   SetShadowTransform(aLayer, layerTransform);
     280           0 :   aLayer->AsHostLayer()->SetShadowTransformSetByAnimation(false);
     281             : 
     282           0 :   if (aAdjustClipRect) {
     283           0 :     auto transform = ParentLayerToParentLayerMatrix4x4::Translation(aTranslation);
     284             :     // If we're passed a clip parts cache, only transform the fixed part of
     285             :     // the clip.
     286           0 :     if (aClipPartsCache) {
     287           0 :       auto iter = aClipPartsCache->find(aLayer);
     288           0 :       MOZ_ASSERT(iter != aClipPartsCache->end());
     289           0 :       TransformFixedClip(aLayer, transform, iter->second);
     290             :     } else {
     291           0 :       TransformClipRect(aLayer, transform);
     292             :     }
     293             : 
     294             :     // If a fixed- or sticky-position layer has a mask layer, that mask should
     295             :     // move along with the layer, so apply the translation to the mask layer too.
     296           0 :     if (Layer* maskLayer = aLayer->GetMaskLayer()) {
     297           0 :       TranslateShadowLayer(maskLayer, aTranslation, false, aClipPartsCache);
     298             :     }
     299             :   }
     300           0 : }
     301             : 
     302             : #ifdef DEBUG
     303             : static void
     304           0 : AccumulateLayerTransforms(Layer* aLayer,
     305             :                           Layer* aAncestor,
     306             :                           Matrix4x4& aMatrix)
     307             : {
     308             :   // Accumulate the transforms between this layer and the subtree root layer.
     309           0 :   for (Layer* l = aLayer; l && l != aAncestor; l = l->GetParent()) {
     310           0 :     Matrix4x4 transform;
     311           0 :     GetBaseTransform(l, &transform);
     312           0 :     aMatrix *= transform;
     313             :   }
     314           0 : }
     315             : #endif
     316             : 
     317             : static LayerPoint
     318           0 : GetLayerFixedMarginsOffset(Layer* aLayer,
     319             :                            const ScreenMargin& aFixedLayerMargins)
     320             : {
     321             :   // Work out the necessary translation, in root scrollable layer space.
     322             :   // Because fixed layer margins are stored relative to the root scrollable
     323             :   // layer, we can just take the difference between these values.
     324           0 :   LayerPoint translation;
     325           0 :   int32_t sides = aLayer->GetFixedPositionSides();
     326             : 
     327           0 :   if ((sides & eSideBitsLeftRight) == eSideBitsLeftRight) {
     328           0 :     translation.x += (aFixedLayerMargins.left - aFixedLayerMargins.right) / 2;
     329           0 :   } else if (sides & eSideBitsRight) {
     330           0 :     translation.x -= aFixedLayerMargins.right;
     331           0 :   } else if (sides & eSideBitsLeft) {
     332           0 :     translation.x += aFixedLayerMargins.left;
     333             :   }
     334             : 
     335           0 :   if ((sides & eSideBitsTopBottom) == eSideBitsTopBottom) {
     336           0 :     translation.y += (aFixedLayerMargins.top - aFixedLayerMargins.bottom) / 2;
     337           0 :   } else if (sides & eSideBitsBottom) {
     338           0 :     translation.y -= aFixedLayerMargins.bottom;
     339           0 :   } else if (sides & eSideBitsTop) {
     340           0 :     translation.y += aFixedLayerMargins.top;
     341             :   }
     342             : 
     343           0 :   return translation;
     344             : }
     345             : 
     346             : static gfxFloat
     347           0 : IntervalOverlap(gfxFloat aTranslation, gfxFloat aMin, gfxFloat aMax)
     348             : {
     349             :   // Determine the amount of overlap between the 1D vector |aTranslation|
     350             :   // and the interval [aMin, aMax].
     351           0 :   if (aTranslation > 0) {
     352           0 :     return std::max(0.0, std::min(aMax, aTranslation) - std::max(aMin, 0.0));
     353             :   } else {
     354           0 :     return std::min(0.0, std::max(aMin, aTranslation) - std::min(aMax, 0.0));
     355             :   }
     356             : }
     357             : 
     358             : /**
     359             :  * Finds the metrics on |aLayer| with scroll id |aScrollId|, and returns a
     360             :  * LayerMetricsWrapper representing the (layer, metrics) pair, or the null
     361             :  * LayerMetricsWrapper if no matching metrics could be found.
     362             :  */
     363             : static LayerMetricsWrapper
     364           0 : FindMetricsWithScrollId(Layer* aLayer, FrameMetrics::ViewID aScrollId)
     365             : {
     366           0 :   for (uint64_t i = 0; i < aLayer->GetScrollMetadataCount(); ++i) {
     367           0 :     if (aLayer->GetFrameMetrics(i).GetScrollId() == aScrollId) {
     368           0 :       return LayerMetricsWrapper(aLayer, i);
     369             :     }
     370             :   }
     371           0 :   return LayerMetricsWrapper();
     372             : }
     373             : 
     374             : /**
     375             :  * Checks whether the (layer, metrics) pair (aTransformedLayer, aTransformedMetrics)
     376             :  * is on the path from |aFixedLayer| to the metrics with scroll id
     377             :  * |aFixedWithRespectTo|, inclusive.
     378             :  */
     379             : static bool
     380           0 : AsyncTransformShouldBeUnapplied(Layer* aFixedLayer,
     381             :                                 FrameMetrics::ViewID aFixedWithRespectTo,
     382             :                                 Layer* aTransformedLayer,
     383             :                                 FrameMetrics::ViewID aTransformedMetrics)
     384             : {
     385           0 :   LayerMetricsWrapper transformed = FindMetricsWithScrollId(aTransformedLayer, aTransformedMetrics);
     386           0 :   if (!transformed.IsValid()) {
     387           0 :     return false;
     388             :   }
     389             :   // It's important to start at the bottom, because the fixed layer itself
     390             :   // could have the transformed metrics, and they can be at the bottom.
     391           0 :   LayerMetricsWrapper current(aFixedLayer, LayerMetricsWrapper::StartAt::BOTTOM);
     392           0 :   bool encounteredTransformedLayer = false;
     393             :   // The transformed layer is on the path from |aFixedLayer| to the fixed-to
     394             :   // layer if as we walk up the (layer, metrics) tree starting from
     395             :   // |aFixedLayer|, we *first* encounter the transformed layer, and *then* (or
     396             :   // at the same time) the fixed-to layer.
     397           0 :   while (current) {
     398           0 :     if (!encounteredTransformedLayer && current == transformed) {
     399           0 :       encounteredTransformedLayer = true;
     400             :     }
     401           0 :     if (current.Metrics().GetScrollId() == aFixedWithRespectTo) {
     402           0 :       return encounteredTransformedLayer;
     403             :     }
     404           0 :     current = current.GetParent();
     405             :     // It's possible that we reach a layers id boundary before we reach an
     406             :     // ancestor with the scroll id |aFixedWithRespectTo| (this could happen
     407             :     // e.g. if the scroll frame with that scroll id uses containerless
     408             :     // scrolling). In such a case, stop the walk, as a new layers id could
     409             :     // have a different layer with scroll id |aFixedWithRespectTo| which we
     410             :     // don't intend to match.
     411           0 :     if (current && current.AsRefLayer() != nullptr) {
     412           0 :       break;
     413             :     }
     414             :   }
     415           0 :   return false;
     416             : }
     417             : 
     418             : // If |aLayer| is fixed or sticky, returns the scroll id of the scroll frame
     419             : // that it's fixed or sticky to. Otherwise, returns Nothing().
     420             : static Maybe<FrameMetrics::ViewID>
     421         226 : IsFixedOrSticky(Layer* aLayer)
     422             : {
     423         226 :   bool isRootOfFixedSubtree = aLayer->GetIsFixedPosition() &&
     424         226 :     !aLayer->GetParent()->GetIsFixedPosition();
     425         226 :   if (isRootOfFixedSubtree) {
     426           0 :     return Some(aLayer->GetFixedPositionScrollContainerId());
     427             :   }
     428         226 :   if (aLayer->GetIsStickyPosition()) {
     429           0 :     return Some(aLayer->GetStickyScrollContainerId());
     430             :   }
     431         226 :   return Nothing();
     432             : }
     433             : 
     434             : void
     435         226 : AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aTransformedSubtreeRoot,
     436             :                                                    Layer* aStartTraversalAt,
     437             :                                                    FrameMetrics::ViewID aTransformScrollId,
     438             :                                                    const LayerToParentLayerMatrix4x4& aPreviousTransformForRoot,
     439             :                                                    const LayerToParentLayerMatrix4x4& aCurrentTransformForRoot,
     440             :                                                    const ScreenMargin& aFixedLayerMargins,
     441             :                                                    ClipPartsCache* aClipPartsCache)
     442             : {
     443             :   // We're going to be inverting |aCurrentTransformForRoot|.
     444             :   // If it's singular, there's nothing we can do.
     445         226 :   if (aCurrentTransformForRoot.IsSingular()) {
     446           0 :     return;
     447             :   }
     448             : 
     449         226 :   Layer* layer = aStartTraversalAt;
     450         226 :   bool needsAsyncTransformUnapplied = false;
     451         452 :   if (Maybe<FrameMetrics::ViewID> fixedTo = IsFixedOrSticky(layer)) {
     452           0 :     needsAsyncTransformUnapplied = AsyncTransformShouldBeUnapplied(layer,
     453           0 :         *fixedTo, aTransformedSubtreeRoot, aTransformScrollId);
     454             :   }
     455             : 
     456             :   // We want to process all the fixed and sticky descendants of
     457             :   // aTransformedSubtreeRoot. Once we do encounter such a descendant, we don't
     458             :   // need to recurse any deeper because the adjustment to the fixed or sticky
     459             :   // layer will apply to its subtree.
     460         226 :   if (!needsAsyncTransformUnapplied) {
     461         412 :     for (Layer* child = layer->GetFirstChild(); child; child = child->GetNextSibling()) {
     462             :       AlignFixedAndStickyLayers(aTransformedSubtreeRoot, child,
     463             :           aTransformScrollId, aPreviousTransformForRoot,
     464         186 :           aCurrentTransformForRoot, aFixedLayerMargins, aClipPartsCache);
     465             :     }
     466         226 :     return;
     467             :   }
     468             : 
     469             :   // Insert a translation so that the position of the anchor point is the same
     470             :   // before and after the change to the transform of aTransformedSubtreeRoot.
     471             : 
     472             :   // A transform creates a containing block for fixed-position descendants,
     473             :   // so there shouldn't be a transform in between the fixed layer and
     474             :   // the subtree root layer.
     475             : #ifdef DEBUG
     476           0 :   Matrix4x4 ancestorTransform;
     477           0 :   if (layer != aTransformedSubtreeRoot) {
     478           0 :     AccumulateLayerTransforms(layer->GetParent(), aTransformedSubtreeRoot,
     479           0 :                               ancestorTransform);
     480             :   }
     481           0 :   ancestorTransform.NudgeToIntegersFixedEpsilon();
     482           0 :   MOZ_ASSERT(ancestorTransform.IsIdentity());
     483             : #endif
     484             : 
     485             :   // Since we create container layers for fixed layers, there shouldn't
     486             :   // a local CSS or OMTA transform on the fixed layer, either (any local
     487             :   // transform would go onto a descendant layer inside the container
     488             :   // layer).
     489             : #ifdef DEBUG
     490           0 :   Matrix4x4 localTransform;
     491           0 :   GetBaseTransform(layer, &localTransform);
     492           0 :   localTransform.NudgeToIntegersFixedEpsilon();
     493           0 :   MOZ_ASSERT(localTransform.IsIdentity());
     494             : #endif
     495             : 
     496             :   // Now work out the translation necessary to make sure the layer doesn't
     497             :   // move given the new sub-tree root transform.
     498             : 
     499             :   // Get the layer's fixed anchor point, in the layer's local coordinate space
     500             :   // (before any transform is applied).
     501           0 :   LayerPoint anchor = layer->GetFixedPositionAnchor();
     502             : 
     503             :   // Offset the layer's anchor point to make sure fixed position content
     504             :   // respects content document fixed position margins.
     505           0 :   LayerPoint offsetAnchor = anchor + GetLayerFixedMarginsOffset(layer, aFixedLayerMargins);
     506             : 
     507             :   // Additionally transform the anchor to compensate for the change
     508             :   // from the old transform to the new transform. We do
     509             :   // this by using the old transform to take the offset anchor back into
     510             :   // subtree root space, and then the inverse of the new transform
     511             :   // to bring it back to layer space.
     512             :   ParentLayerPoint offsetAnchorInSubtreeRootSpace =
     513           0 :       aPreviousTransformForRoot.TransformPoint(offsetAnchor);
     514           0 :   LayerPoint transformedAnchor = aCurrentTransformForRoot.Inverse()
     515           0 :       .TransformPoint(offsetAnchorInSubtreeRootSpace);
     516             : 
     517             :   // We want to translate the layer by the difference between
     518             :   // |transformedAnchor| and |anchor|.
     519           0 :   LayerPoint translation = transformedAnchor - anchor;
     520             : 
     521             :   // A fixed layer will "consume" (be unadjusted by) the entire translation
     522             :   // calculated above. A sticky layer may consume all, part, or none of it,
     523             :   // depending on where we are relative to its sticky scroll range.
     524             :   // The remainder of the translation (the unconsumed portion) needs to
     525             :   // be propagated to descendant fixed/sticky layers.
     526           0 :   LayerPoint unconsumedTranslation;
     527             : 
     528           0 :   if (layer->GetIsStickyPosition()) {
     529             :     // For sticky positioned layers, the difference between the two rectangles
     530             :     // defines a pair of translation intervals in each dimension through which
     531             :     // the layer should not move relative to the scroll container. To
     532             :     // accomplish this, we limit each dimension of the |translation| to that
     533             :     // part of it which overlaps those intervals.
     534           0 :     const LayerRect& stickyOuter = layer->GetStickyScrollRangeOuter();
     535           0 :     const LayerRect& stickyInner = layer->GetStickyScrollRangeInner();
     536             : 
     537           0 :     LayerPoint originalTranslation = translation;
     538           0 :     translation.y = IntervalOverlap(translation.y, stickyOuter.y, stickyOuter.YMost()) -
     539           0 :                     IntervalOverlap(translation.y, stickyInner.y, stickyInner.YMost());
     540           0 :     translation.x = IntervalOverlap(translation.x, stickyOuter.x, stickyOuter.XMost()) -
     541           0 :                     IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost());
     542           0 :     unconsumedTranslation = translation - originalTranslation;
     543             :   }
     544             : 
     545             :   // Finally, apply the translation to the layer transform. Note that in cases
     546             :   // where the async transform on |aTransformedSubtreeRoot| affects this layer's
     547             :   // clip rect, we need to apply the same translation to said clip rect, so
     548             :   // that the effective transform on the clip rect takes it back to where it was
     549             :   // originally, had there been no async scroll.
     550           0 :   TranslateShadowLayer(layer, ViewAs<ParentLayerPixel>(translation,
     551           0 :       PixelCastJustification::NoTransformOnLayer), true, aClipPartsCache);
     552             : 
     553             :   // Propragate the unconsumed portion of the translation to descendant
     554             :   // fixed/sticky layers.
     555           0 :   if (unconsumedTranslation != LayerPoint()) {
     556             :     // Take the computations we performed to derive |translation| from
     557             :     // |aCurrentTransformForRoot|, and perform them in reverse, keeping other
     558             :     // quantities fixed, to come up with a new transform |newTransform| that
     559             :     // would produce |unconsumedTranslation|.
     560           0 :     LayerPoint newTransformedAnchor = unconsumedTranslation + anchor;
     561             :     ParentLayerPoint newTransformedAnchorInSubtreeRootSpace =
     562           0 :         aPreviousTransformForRoot.TransformPoint(newTransformedAnchor);
     563           0 :     LayerToParentLayerMatrix4x4 newTransform = aPreviousTransformForRoot;
     564           0 :     newTransform.PostTranslate(newTransformedAnchorInSubtreeRootSpace -
     565           0 :                                offsetAnchorInSubtreeRootSpace);
     566             : 
     567             :     // Propagate this new transform to our descendants as the new value of
     568             :     // |aCurrentTransformForRoot|. This allows them to consume the unconsumed
     569             :     // translation.
     570           0 :     for (Layer* child = layer->GetFirstChild(); child; child = child->GetNextSibling()) {
     571             :       AlignFixedAndStickyLayers(aTransformedSubtreeRoot, child, aTransformScrollId,
     572           0 :           aPreviousTransformForRoot, newTransform, aFixedLayerMargins, aClipPartsCache);
     573             :     }
     574             :   }
     575             : 
     576           0 :   return;
     577             : }
     578             : 
     579             : static void
     580           0 : ApplyAnimatedValue(Layer* aLayer,
     581             :                    CompositorAnimationStorage* aStorage,
     582             :                    nsCSSPropertyID aProperty,
     583             :                    const AnimationData& aAnimationData,
     584             :                    const StyleAnimationValue& aValue)
     585             : {
     586           0 :   if (aValue.IsNull()) {
     587             :     // Return gracefully if we have no valid StyleAnimationValue.
     588           0 :     return;
     589             :   }
     590             : 
     591           0 :   HostLayer* layerCompositor = aLayer->AsHostLayer();
     592           0 :   switch (aProperty) {
     593             :     case eCSSProperty_opacity: {
     594           0 :       MOZ_ASSERT(aValue.GetUnit() == StyleAnimationValue::eUnit_Float,
     595             :                  "Interpolated value for opacity should be float");
     596           0 :       layerCompositor->SetShadowOpacity(aValue.GetFloatValue());
     597           0 :       layerCompositor->SetShadowOpacitySetByAnimation(true);
     598           0 :       aStorage->SetAnimatedValue(aLayer->GetCompositorAnimationsId(),
     599           0 :                                  aValue.GetFloatValue());
     600             : 
     601           0 :       break;
     602             :     }
     603             :     case eCSSProperty_transform: {
     604           0 :       MOZ_ASSERT(aValue.GetUnit() == StyleAnimationValue::eUnit_Transform,
     605             :                  "The unit of interpolated value for transform should be "
     606             :                  "transform");
     607           0 :       nsCSSValueSharedList* list = aValue.GetCSSValueSharedListValue();
     608             : 
     609           0 :       const TransformData& transformData = aAnimationData.get_TransformData();
     610           0 :       nsPoint origin = transformData.origin();
     611             :       // we expect all our transform data to arrive in device pixels
     612           0 :       Point3D transformOrigin = transformData.transformOrigin();
     613             :       nsDisplayTransform::FrameTransformProperties props(list,
     614           0 :                                                          transformOrigin);
     615             : 
     616             :       Matrix4x4 transform =
     617             :         nsDisplayTransform::GetResultingTransformMatrix(props, origin,
     618           0 :                                                         transformData.appUnitsPerDevPixel(),
     619           0 :                                                         0, &transformData.bounds());
     620           0 :       Matrix4x4 frameTransform = transform;
     621             : 
     622             :       // If our parent layer is a perspective layer, then the offset into reference
     623             :       // frame coordinates is already on that layer. If not, then we need to ask
     624             :       // for it to be added here.
     625           0 :       if (!aLayer->GetParent() ||
     626           0 :           !aLayer->GetParent()->GetTransformIsPerspective()) {
     627           0 :         nsLayoutUtils::PostTranslate(transform, origin,
     628           0 :                                      transformData.appUnitsPerDevPixel(),
     629           0 :                                      true);
     630             :       }
     631             : 
     632           0 :       if (ContainerLayer* c = aLayer->AsContainerLayer()) {
     633           0 :         transform.PostScale(c->GetInheritedXScale(), c->GetInheritedYScale(), 1);
     634             :       }
     635             : 
     636           0 :       layerCompositor->SetShadowBaseTransform(transform);
     637           0 :       layerCompositor->SetShadowTransformSetByAnimation(true);
     638           0 :       aStorage->SetAnimatedValue(aLayer->GetCompositorAnimationsId(),
     639           0 :                                  Move(transform), Move(frameTransform),
     640           0 :                                  transformData);
     641           0 :       break;
     642             :     }
     643             :     default:
     644           0 :       MOZ_ASSERT_UNREACHABLE("Unhandled animated property");
     645             :   }
     646             : }
     647             : 
     648             : static AnimationProcessTypes
     649          29 : SampleAnimations(Layer* aLayer,
     650             :                  CompositorAnimationStorage* aStorage,
     651             :                  TimeStamp aTime,
     652             :                  uint64_t* aLayerAreaAnimated)
     653             : {
     654             :   // This tracks the first-encountered RefLayer in the layer tree. Since we are
     655             :   // doing a depth-first traversal, it is set to a non-null value if and only if
     656             :   // the currently-being-traversed node has a RefLayer ancestor. In the case of
     657             :   // nested RefLayers it points to the rootmost RefLayer.
     658          29 :   RefLayer* ancestorRefLayer = nullptr;
     659             : 
     660             :   // This bitfield-enum tracks which processes have active animations. Anything
     661             :   // "above" the |ancestorRefLayer| in the layer tree is assumed to be the
     662             :   // chrome process, and anything "below" is assumed to be the content process.
     663          29 :   AnimationProcessTypes animProcess = AnimationProcessTypes::eNone;
     664             : 
     665          58 :   ForEachNode<ForwardIterator>(
     666             :       aLayer,
     667         215 :       [&] (Layer* layer)
     668             :       {
     669         215 :         if (!ancestorRefLayer) {
     670         165 :           ancestorRefLayer = layer->AsRefLayer();
     671             :         }
     672             : 
     673         215 :         bool hasInEffectAnimations = false;
     674         430 :         StyleAnimationValue animationValue = layer->GetBaseAnimationStyle();
     675         430 :         if (AnimationHelper::SampleAnimationForEachNode(aTime,
     676         215 :                                                         layer->GetAnimations(),
     677             :                                                         layer->GetAnimationData(),
     678             :                                                         animationValue,
     679             :                                                         hasInEffectAnimations)) {
     680           0 :           animProcess |= (ancestorRefLayer ? AnimationProcessTypes::eContent
     681           0 :                                            : AnimationProcessTypes::eChrome);
     682             :         }
     683         215 :         if (hasInEffectAnimations) {
     684           0 :           Animation& animation = layer->GetAnimations().LastElement();
     685           0 :           ApplyAnimatedValue(layer,
     686           0 :                              aStorage,
     687           0 :                              animation.property(),
     688           0 :                              animation.data(),
     689           0 :                              animationValue);
     690           0 :           if (aLayerAreaAnimated) {
     691           0 :             *aLayerAreaAnimated += (layer->GetVisibleRegion().Area());
     692             :           }
     693             :         }
     694         215 :       },
     695         215 :       [&ancestorRefLayer] (Layer* aLayer)
     696         323 :       {
     697             :         // If we're unwinding up past the rootmost RefLayer, clear our pointer
     698         294 :         if (ancestorRefLayer && aLayer->AsRefLayer() == ancestorRefLayer) {
     699          29 :           ancestorRefLayer = nullptr;
     700             :         }
     701         244 :       });
     702             : 
     703          29 :   return animProcess;
     704             : }
     705             : 
     706             : static bool
     707          29 : SampleAPZAnimations(const LayerMetricsWrapper& aLayer, TimeStamp aSampleTime)
     708             : {
     709          29 :   bool activeAnimations = false;
     710             : 
     711          58 :   ForEachNodePostOrder<ForwardIterator>(aLayer,
     712         215 :       [&activeAnimations, &aSampleTime](LayerMetricsWrapper aLayerMetrics)
     713         120 :       {
     714         215 :         if (AsyncPanZoomController* apzc = aLayerMetrics.GetApzc()) {
     715          40 :           apzc->ReportCheckerboard(aSampleTime);
     716          80 :           activeAnimations |= apzc->AdvanceAnimations(aSampleTime);
     717             :         }
     718         215 :       }
     719          29 :   );
     720             : 
     721          29 :   return activeAnimations;
     722             : }
     723             : 
     724             : void
     725           0 : AsyncCompositionManager::RecordShadowTransforms(Layer* aLayer)
     726             : {
     727           0 :   MOZ_ASSERT(gfxPrefs::CollectScrollTransforms());
     728           0 :   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
     729             : 
     730           0 :   ForEachNodePostOrder<ForwardIterator>(
     731             :       aLayer,
     732           0 :       [this] (Layer* layer)
     733           0 :       {
     734           0 :         for (uint32_t i = 0; i < layer->GetScrollMetadataCount(); i++) {
     735           0 :           AsyncPanZoomController* apzc = layer->GetAsyncPanZoomController(i);
     736           0 :           if (!apzc) {
     737           0 :             continue;
     738             :           }
     739           0 :           gfx::Matrix4x4 shadowTransform = layer->AsHostLayer()->GetShadowBaseTransform();
     740           0 :           if (!shadowTransform.Is2D()) {
     741           0 :             continue;
     742             :           }
     743             : 
     744           0 :           Matrix transform = shadowTransform.As2D();
     745           0 :           if (transform.IsTranslation() && !shadowTransform.IsIdentity()) {
     746           0 :             Point translation = transform.GetTranslation();
     747           0 :             mLayerTransformRecorder.RecordTransform(layer, translation);
     748           0 :             return;
     749             :           }
     750             :         }
     751           0 :       });
     752           0 : }
     753             : 
     754             : static AsyncTransformComponentMatrix
     755          80 : AdjustForClip(const AsyncTransformComponentMatrix& asyncTransform, Layer* aLayer)
     756             : {
     757          80 :   AsyncTransformComponentMatrix result = asyncTransform;
     758             : 
     759             :   // Container layers start at the origin, but they are clipped to where they
     760             :   // actually have content on the screen. The tree transform is meant to apply
     761             :   // to the clipped area. If the tree transform includes a scale component,
     762             :   // then applying it to container as-is will produce incorrect results. To
     763             :   // avoid this, translate the layer so that the clip rect starts at the origin,
     764             :   // apply the tree transform, and translate back.
     765          80 :   if (const Maybe<ParentLayerIntRect>& shadowClipRect = aLayer->AsHostLayer()->GetShadowClipRect()) {
     766          16 :     if (shadowClipRect->TopLeft() != ParentLayerIntPoint()) {  // avoid a gratuitous change of basis
     767           0 :       result.ChangeBasis(shadowClipRect->x, shadowClipRect->y, 0);
     768             :     }
     769             :   }
     770          80 :   return result;
     771             : }
     772             : 
     773             : static void
     774         215 : ExpandRootClipRect(Layer* aLayer, const ScreenMargin& aFixedLayerMargins)
     775             : {
     776             :   // For Fennec we want to expand the root scrollable layer clip rect based on
     777             :   // the fixed position margins. In particular, we want this while the dynamic
     778             :   // toolbar is in the process of sliding offscreen and the area of the
     779             :   // LayerView visible to the user is larger than the viewport size that Gecko
     780             :   // knows about (and therefore larger than the clip rect). We could also just
     781             :   // clear the clip rect on aLayer entirely but this seems more precise.
     782         430 :   Maybe<ParentLayerIntRect> rootClipRect = aLayer->AsHostLayer()->GetShadowClipRect();
     783         215 :   if (rootClipRect && aFixedLayerMargins != ScreenMargin()) {
     784             : #ifndef MOZ_WIDGET_ANDROID
     785             :     // We should never enter here on anything other than Fennec, since
     786             :     // aFixedLayerMargins should be empty everywhere else.
     787           0 :     MOZ_ASSERT(false);
     788             : #endif
     789             :     ParentLayerRect rect(rootClipRect.value());
     790             :     rect.Deflate(ViewAs<ParentLayerPixel>(aFixedLayerMargins,
     791             :       PixelCastJustification::ScreenIsParentLayerForRoot));
     792             :     aLayer->AsHostLayer()->SetShadowClipRect(Some(RoundedOut(rect)));
     793             :   }
     794         215 : }
     795             : 
     796             : #ifdef MOZ_WIDGET_ANDROID
     797             : static void
     798             : MoveScrollbarForLayerMargin(Layer* aRoot, FrameMetrics::ViewID aRootScrollId,
     799             :                             const ScreenMargin& aFixedLayerMargins)
     800             : {
     801             :   // See bug 1223928 comment 9 - once we can detect the RCD with just the
     802             :   // isRootContent flag on the metrics, we can probably move this code into
     803             :   // ApplyAsyncTransformToScrollbar rather than having it as a separate
     804             :   // adjustment on the layer tree.
     805             :   Layer* scrollbar = BreadthFirstSearch<ReverseIterator>(aRoot,
     806             :     [aRootScrollId](Layer* aNode) {
     807             :       return (aNode->GetScrollThumbData().mDirection == ScrollDirection::HORIZONTAL &&
     808             :               aNode->GetScrollbarTargetContainerId() == aRootScrollId);
     809             :     });
     810             :   if (scrollbar) {
     811             :     // Shift the horizontal scrollbar down into the new space exposed by the
     812             :     // dynamic toolbar hiding. Technically we should also scale the vertical
     813             :     // scrollbar a bit to expand into the new space but it's not as noticeable
     814             :     // and it would add a lot more complexity, so we're going with the "it's not
     815             :     // worth it" justification.
     816             :     TranslateShadowLayer(scrollbar, ParentLayerPoint(0, -aFixedLayerMargins.bottom), true, nullptr);
     817             :     if (scrollbar->GetParent()) {
     818             :       // The layer that has the HORIZONTAL direction sits inside another
     819             :       // ContainerLayer. This ContainerLayer also has a clip rect that causes
     820             :       // the scrollbar to get clipped. We need to expand that clip rect to
     821             :       // prevent that from happening. This is kind of ugly in that we're
     822             :       // assuming a particular layer tree structure but short of adding more
     823             :       // flags to the layer there doesn't appear to be a good way to do this.
     824             :       ExpandRootClipRect(scrollbar->GetParent(), aFixedLayerMargins);
     825             :     }
     826             :   }
     827             : }
     828             : #endif
     829             : 
     830             : bool
     831          29 : AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
     832             :                                                           bool* aOutFoundRoot)
     833             : {
     834          29 :   bool appliedTransform = false;
     835          58 :   std::stack<Maybe<ParentLayerIntRect>> stackDeferredClips;
     836             : 
     837             :   // Maps layers to their ClipParts. The parts are not stored individually
     838             :   // on the layer, but during AlignFixedAndStickyLayers we need access to
     839             :   // the individual parts for descendant layers.
     840          58 :   ClipPartsCache clipPartsCache;
     841             : 
     842          58 :   ForEachNode<ForwardIterator>(
     843             :       aLayer,
     844         215 :       [&stackDeferredClips] (Layer* layer)
     845         215 :       {
     846         430 :         stackDeferredClips.push(Maybe<ParentLayerIntRect>());
     847         215 :       },
     848         215 :       [this, &aOutFoundRoot, &stackDeferredClips, &appliedTransform, &clipPartsCache] (Layer* layer)
     849         845 :       {
     850         430 :         Maybe<ParentLayerIntRect> clipDeferredFromChildren = stackDeferredClips.top();
     851         215 :         stackDeferredClips.pop();
     852         430 :         LayerToParentLayerMatrix4x4 oldTransform = layer->GetTransformTyped() *
     853         645 :             AsyncTransformMatrix();
     854             : 
     855         215 :         AsyncTransformComponentMatrix combinedAsyncTransform;
     856         215 :         bool hasAsyncTransform = false;
     857             :         // Only set on the root layer for Android.
     858         215 :         ScreenMargin fixedLayerMargins;
     859             : 
     860             :         // Each layer has multiple clips:
     861             :         //  - Its local clip, which is fixed to the layer contents, i.e. it moves
     862             :         //    with those async transforms which the layer contents move with.
     863             :         //  - Its scrolled clip, which moves with all async transforms.
     864             :         //  - For each ScrollMetadata on the layer, a scroll clip. This includes
     865             :         //    the composition bounds and any other clips induced by layout. This
     866             :         //    moves with async transforms from ScrollMetadatas above it.
     867             :         // In this function, these clips are combined into two shadow clip parts:
     868             :         //  - The fixed clip, which consists of the local clip only, initially
     869             :         //    transformed by all async transforms.
     870             :         //  - The scrolled clip, which consists of the other clips, transformed by
     871             :         //    the appropriate transforms.
     872             :         // These two parts are kept separate for now, because for fixed layers, we
     873             :         // need to adjust the fixed clip (to cancel out some async transforms).
     874             :         // The parts are kept in a cache which is cleared at the beginning of every
     875             :         // composite.
     876             :         // The final shadow clip for the layer is the intersection of the (possibly
     877             :         // adjusted) fixed clip and the scrolled clip.
     878         215 :         ClipParts& clipParts = clipPartsCache[layer];
     879         215 :         clipParts.mFixedClip = layer->GetClipRect();
     880         215 :         clipParts.mScrolledClip = layer->GetScrolledClipRect();
     881             : 
     882             :         // If we are a perspective transform ContainerLayer, apply the clip deferred
     883             :         // from our child (if there is any) before we iterate over our frame metrics,
     884             :         // because this clip is subject to all async transforms of this layer.
     885             :         // Since this clip came from the a scroll clip on the child, it becomes part
     886             :         // of our scrolled clip.
     887         430 :         clipParts.mScrolledClip = IntersectMaybeRects(
     888         215 :             clipDeferredFromChildren, clipParts.mScrolledClip);
     889             : 
     890             :         // The transform of a mask layer is relative to the masked layer's parent
     891             :         // layer. So whenever we apply an async transform to a layer, we need to
     892             :         // apply that same transform to the layer's own mask layer.
     893             :         // A layer can also have "ancestor" mask layers for any rounded clips from
     894             :         // its ancestor scroll frames. A scroll frame mask layer only needs to be
     895             :         // async transformed for async scrolls of this scroll frame's ancestor
     896             :         // scroll frames, not for async scrolls of this scroll frame itself.
     897             :         // In the loop below, we iterate over scroll frames from inside to outside.
     898             :         // At each iteration, this array contains the layer's ancestor mask layers
     899             :         // of all scroll frames inside the current one.
     900         430 :         nsTArray<Layer*> ancestorMaskLayers;
     901             : 
     902             :         // The layer's scrolled clip can have an ancestor mask layer as well,
     903             :         // which is moved by all async scrolls on this layer.
     904         215 :         if (const Maybe<LayerClip>& scrolledClip = layer->GetScrolledClip()) {
     905           0 :           if (scrolledClip->GetMaskLayerIndex()) {
     906             :             ancestorMaskLayers.AppendElement(
     907           0 :                 layer->GetAncestorMaskLayerAt(*scrolledClip->GetMaskLayerIndex()));
     908             :           }
     909             :         }
     910             : 
     911         255 :         for (uint32_t i = 0; i < layer->GetScrollMetadataCount(); i++) {
     912          40 :           AsyncPanZoomController* controller = layer->GetAsyncPanZoomController(i);
     913          40 :           if (!controller) {
     914           0 :             continue;
     915             :           }
     916             : 
     917          40 :           hasAsyncTransform = true;
     918             : 
     919             :           AsyncTransform asyncTransformWithoutOverscroll =
     920          40 :               controller->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing);
     921             :           AsyncTransformComponentMatrix overscrollTransform =
     922          40 :               controller->GetOverscrollTransform(AsyncPanZoomController::eForCompositing);
     923             :           AsyncTransformComponentMatrix asyncTransform =
     924          80 :               AsyncTransformComponentMatrix(asyncTransformWithoutOverscroll)
     925          40 :             * overscrollTransform;
     926             : 
     927          40 :           if (!layer->IsScrollInfoLayer()) {
     928          40 :             controller->MarkAsyncTransformAppliedToContent();
     929             :           }
     930             : 
     931          40 :           const ScrollMetadata& scrollMetadata = layer->GetScrollMetadata(i);
     932          40 :           const FrameMetrics& metrics = scrollMetadata.GetMetrics();
     933             : 
     934             : #if defined(MOZ_WIDGET_ANDROID)
     935             :           // If we find a metrics which is the root content doc, use that. If not, use
     936             :           // the root layer. Since this function recurses on children first we should
     937             :           // only end up using the root layer if the entire tree was devoid of a
     938             :           // root content metrics. This is a temporary solution; in the long term we
     939             :           // should not need the root content metrics at all. See bug 1201529 comment
     940             :           // 6 for details.
     941             :           if (!(*aOutFoundRoot)) {
     942             :             *aOutFoundRoot = metrics.IsRootContent() ||       /* RCD */
     943             :                   (layer->GetParent() == nullptr &&          /* rootmost metrics */
     944             :                    i + 1 >= layer->GetScrollMetadataCount());
     945             :             if (*aOutFoundRoot) {
     946             :               mRootScrollableId = metrics.GetScrollId();
     947             :               Compositor* compositor = mLayerManager->GetCompositor();
     948             :               if (CompositorBridgeParent* bridge = compositor->GetCompositorBridgeParent()) {
     949             :                 AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
     950             :                 MOZ_ASSERT(animator);
     951             :                 if (mIsFirstPaint) {
     952             :                   animator->UpdateRootFrameMetrics(metrics);
     953             :                   animator->FirstPaint();
     954             :                   mIsFirstPaint = false;
     955             :                 }
     956             :                 if (mLayersUpdated) {
     957             :                   animator->NotifyLayersUpdated();
     958             :                   mLayersUpdated = false;
     959             :                 }
     960             :                 // If this is not actually the root content then the animator is not getting updated in AsyncPanZoomController::NotifyLayersUpdated
     961             :                 // because the root content document is not scrollable. So update it here so it knows if the root composition size has changed.
     962             :                 if (!metrics.IsRootContent()) {
     963             :                   animator->MaybeUpdateCompositionSizeAndRootFrameMetrics(metrics);
     964             :                 }
     965             :               }
     966             :               fixedLayerMargins = mFixedLayerMargins;
     967             :             }
     968             :           }
     969             : #else
     970          40 :           *aOutFoundRoot = false;
     971             :           // Non-Android platforms still care about this flag being cleared after
     972             :           // the first call to TransformShadowTree().
     973          40 :           mIsFirstPaint = false;
     974             : #endif
     975             : 
     976             :           // Transform the current local clips by this APZC's async transform. If we're
     977             :           // using containerful scrolling, then the clip is not part of the scrolled
     978             :           // frame and should not be transformed.
     979          40 :           if (!scrollMetadata.UsesContainerScrolling()) {
     980          40 :             MOZ_ASSERT(asyncTransform.Is2D());
     981          40 :             if (clipParts.mFixedClip) {
     982           5 :               *clipParts.mFixedClip = TransformBy(asyncTransform, *clipParts.mFixedClip);
     983             :             }
     984          40 :             if (clipParts.mScrolledClip) {
     985           0 :               *clipParts.mScrolledClip = TransformBy(asyncTransform, *clipParts.mScrolledClip);
     986             :             }
     987             :           }
     988             :           // Note: we don't set the layer's shadow clip rect property yet;
     989             :           // AlignFixedAndStickyLayers will use the clip parts from the clip parts
     990             :           // cache.
     991             : 
     992          40 :           combinedAsyncTransform *= asyncTransform;
     993             : 
     994             :           // For the purpose of aligning fixed and sticky layers, we disregard
     995             :           // the overscroll transform as well as any OMTA transform when computing the
     996             :           // 'aCurrentTransformForRoot' parameter. This ensures that the overscroll
     997             :           // and OMTA transforms are not unapplied, and therefore that the visual
     998             :           // effects apply to fixed and sticky layers. We do this by using
     999             :           // GetTransform() as the base transform rather than GetLocalTransform(),
    1000             :           // which would include those factors.
    1001             :           LayerToParentLayerMatrix4x4 transformWithoutOverscrollOrOmta =
    1002          80 :               layer->GetTransformTyped()
    1003          80 :             * CompleteAsyncTransform(
    1004         120 :                 AdjustForClip(asyncTransformWithoutOverscroll, layer));
    1005             : 
    1006          40 :           AlignFixedAndStickyLayers(layer, layer, metrics.GetScrollId(), oldTransform,
    1007             :                                     transformWithoutOverscrollOrOmta, fixedLayerMargins,
    1008          80 :                                     &clipPartsCache);
    1009             : 
    1010             :           // Combine the local clip with the ancestor scrollframe clip. This is not
    1011             :           // included in the async transform above, since the ancestor clip should not
    1012             :           // move with this APZC.
    1013          40 :           if (scrollMetadata.HasScrollClip()) {
    1014          11 :             ParentLayerIntRect clip = scrollMetadata.ScrollClip().GetClipRect();
    1015          11 :             if (layer->GetParent() && layer->GetParent()->GetTransformIsPerspective()) {
    1016             :               // If our parent layer has a perspective transform, we want to apply
    1017             :               // our scroll clip to it instead of to this layer (see bug 1168263).
    1018             :               // A layer with a perspective transform shouldn't have multiple
    1019             :               // children with FrameMetrics, nor a child with multiple FrameMetrics.
    1020             :               // (A child with multiple FrameMetrics would mean that there's *another*
    1021             :               // scrollable element between the one with the CSS perspective and the
    1022             :               // transformed element. But you'd have to use preserve-3d on the inner
    1023             :               // scrollable element in order to have the perspective apply to the
    1024             :               // transformed child, and preserve-3d is not supported on scrollable
    1025             :               // elements, so this case can't occur.)
    1026           0 :               MOZ_ASSERT(!stackDeferredClips.top());
    1027           0 :               stackDeferredClips.top().emplace(clip);
    1028             :             } else {
    1029          22 :               clipParts.mScrolledClip = IntersectMaybeRects(Some(clip),
    1030          11 :                   clipParts.mScrolledClip);
    1031             :             }
    1032             :           }
    1033             : 
    1034             :           // Do the same for the ancestor mask layers: ancestorMaskLayers contains
    1035             :           // the ancestor mask layers for scroll frames *inside* the current scroll
    1036             :           // frame, so these are the ones we need to shift by our async transform.
    1037          40 :           for (Layer* ancestorMaskLayer : ancestorMaskLayers) {
    1038             :             SetShadowTransform(ancestorMaskLayer,
    1039           0 :                 ancestorMaskLayer->GetLocalTransformTyped() * asyncTransform);
    1040             :           }
    1041             : 
    1042             :           // Append the ancestor mask layer for this scroll frame to ancestorMaskLayers.
    1043          40 :           if (scrollMetadata.HasScrollClip()) {
    1044          11 :             const LayerClip& scrollClip = scrollMetadata.ScrollClip();
    1045          11 :             if (scrollClip.GetMaskLayerIndex()) {
    1046           0 :               size_t maskLayerIndex = scrollClip.GetMaskLayerIndex().value();
    1047           0 :               Layer* ancestorMaskLayer = layer->GetAncestorMaskLayerAt(maskLayerIndex);
    1048           0 :               ancestorMaskLayers.AppendElement(ancestorMaskLayer);
    1049             :             }
    1050             :           }
    1051             :         }
    1052             : 
    1053         565 :         bool clipChanged = (hasAsyncTransform || clipDeferredFromChildren ||
    1054         565 :                             layer->GetScrolledClipRect());
    1055         215 :         if (clipChanged) {
    1056             :           // Intersect the two clip parts and apply them to the layer.
    1057             :           // During ApplyAsyncContentTransformTree on an ancestor layer,
    1058             :           // AlignFixedAndStickyLayers may overwrite this with a new clip it
    1059             :           // computes from the clip parts, but if that doesn't happen, this
    1060             :           // is the layer's final clip rect.
    1061          40 :           layer->AsHostLayer()->SetShadowClipRect(clipParts.Intersect());
    1062             :         }
    1063             : 
    1064         215 :         if (hasAsyncTransform) {
    1065             :           // Apply the APZ transform on top of GetLocalTransform() here (rather than
    1066             :           // GetTransform()) in case the OMTA code in SampleAnimations already set a
    1067             :           // shadow transform; in that case we want to apply ours on top of that one
    1068             :           // rather than clobber it.
    1069             :           SetShadowTransform(layer,
    1070          80 :               layer->GetLocalTransformTyped()
    1071         120 :             * AdjustForClip(combinedAsyncTransform, layer));
    1072             : 
    1073             :           // Do the same for the layer's own mask layer, if it has one.
    1074          40 :           if (Layer* maskLayer = layer->GetMaskLayer()) {
    1075             :             SetShadowTransform(maskLayer,
    1076           0 :                 maskLayer->GetLocalTransformTyped() * combinedAsyncTransform);
    1077             :           }
    1078             : 
    1079          40 :           appliedTransform = true;
    1080             :         }
    1081             : 
    1082         215 :         ExpandRootClipRect(layer, fixedLayerMargins);
    1083             : 
    1084         215 :         if (layer->GetScrollThumbData().mDirection != ScrollDirection::NONE) {
    1085           0 :           ApplyAsyncTransformToScrollbar(layer);
    1086             :         }
    1087         244 :       });
    1088             : 
    1089          58 :   return appliedTransform;
    1090             : }
    1091             : 
    1092             : static bool
    1093           0 : LayerIsScrollbarTarget(const LayerMetricsWrapper& aTarget, Layer* aScrollbar)
    1094             : {
    1095           0 :   AsyncPanZoomController* apzc = aTarget.GetApzc();
    1096           0 :   if (!apzc) {
    1097           0 :     return false;
    1098             :   }
    1099           0 :   const FrameMetrics& metrics = aTarget.Metrics();
    1100           0 :   if (metrics.GetScrollId() != aScrollbar->GetScrollbarTargetContainerId()) {
    1101           0 :     return false;
    1102             :   }
    1103           0 :   return !aTarget.IsScrollInfoLayer();
    1104             : }
    1105             : 
    1106             : static void
    1107           0 : ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
    1108             :                                          const LayerMetricsWrapper& aContent,
    1109             :                                          bool aScrollbarIsDescendant)
    1110             : {
    1111           0 :   AsyncTransformComponentMatrix clipTransform;
    1112             : 
    1113             :   LayerToParentLayerMatrix4x4 transform =
    1114             :       AsyncCompositionManager::ComputeTransformForScrollThumb(
    1115           0 :           aScrollbar->GetLocalTransformTyped(),
    1116           0 :           aContent.GetTransform(),
    1117             :           aContent.GetApzc(),
    1118             :           aContent.Metrics(),
    1119             :           aScrollbar->GetScrollThumbData(),
    1120             :           aScrollbarIsDescendant,
    1121           0 :           &clipTransform);
    1122             : 
    1123           0 :   if (aScrollbarIsDescendant) {
    1124             :     // We also need to make a corresponding change on the clip rect of all the
    1125             :     // layers on the ancestor chain from the scrollbar layer up to but not
    1126             :     // including the layer with the async transform. Otherwise the scrollbar
    1127             :     // shifts but gets clipped and so appears to flicker.
    1128           0 :     for (Layer* ancestor = aScrollbar; ancestor != aContent.GetLayer(); ancestor = ancestor->GetParent()) {
    1129           0 :       TransformClipRect(ancestor, clipTransform);
    1130             :     }
    1131             :   }
    1132             : 
    1133           0 :   SetShadowTransform(aScrollbar, transform);
    1134           0 : }
    1135             : 
    1136             : /* static */ LayerToParentLayerMatrix4x4
    1137           0 : AsyncCompositionManager::ComputeTransformForScrollThumb(
    1138             :     const LayerToParentLayerMatrix4x4& aCurrentTransform,
    1139             :     const Matrix4x4& aScrollableContentTransform,
    1140             :     AsyncPanZoomController* aApzc,
    1141             :     const FrameMetrics& aMetrics,
    1142             :     const ScrollThumbData& aThumbData,
    1143             :     bool aScrollbarIsDescendant,
    1144             :     AsyncTransformComponentMatrix* aOutClipTransform)
    1145             : {
    1146             :   // We only apply the transform if the scroll-target layer has non-container
    1147             :   // children (i.e. when it has some possibly-visible content). This is to
    1148             :   // avoid moving scroll-bars in the situation that only a scroll information
    1149             :   // layer has been built for a scroll frame, as this would result in a
    1150             :   // disparity between scrollbars and visible content.
    1151           0 :   if (aMetrics.IsScrollInfoLayer()) {
    1152           0 :     return LayerToParentLayerMatrix4x4{};
    1153             :   }
    1154             : 
    1155           0 :   MOZ_RELEASE_ASSERT(aApzc);
    1156             : 
    1157             :   AsyncTransformComponentMatrix asyncTransform =
    1158           0 :     aApzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing);
    1159             : 
    1160             :   // |asyncTransform| represents the amount by which we have scrolled and
    1161             :   // zoomed since the last paint. Because the scrollbar was sized and positioned based
    1162             :   // on the painted content, we need to adjust it based on asyncTransform so that
    1163             :   // it reflects what the user is actually seeing now.
    1164           0 :   AsyncTransformComponentMatrix scrollbarTransform;
    1165           0 :   if (aThumbData.mDirection == ScrollDirection::VERTICAL) {
    1166           0 :     const ParentLayerCoord asyncScrollY = asyncTransform._42;
    1167           0 :     const float asyncZoomY = asyncTransform._22;
    1168             : 
    1169             :     // The scroll thumb needs to be scaled in the direction of scrolling by the
    1170             :     // inverse of the async zoom. This is because zooming in decreases the
    1171             :     // fraction of the whole srollable rect that is in view.
    1172           0 :     const float yScale = 1.f / asyncZoomY;
    1173             : 
    1174             :     // Note: |metrics.GetZoom()| doesn't yet include the async zoom.
    1175           0 :     const CSSToParentLayerScale effectiveZoom(aMetrics.GetZoom().yScale * asyncZoomY);
    1176             : 
    1177             :     // Here we convert the scrollbar thumb ratio into a true unitless ratio by
    1178             :     // dividing out the conversion factor from the scrollframe's parent's space
    1179             :     // to the scrollframe's space.
    1180           0 :     const float ratio = aThumbData.mThumbRatio /
    1181           0 :         (aMetrics.GetPresShellResolution() * asyncZoomY);
    1182             :     // The scroll thumb needs to be translated in opposite direction of the
    1183             :     // async scroll. This is because scrolling down, which translates the layer
    1184             :     // content up, should result in moving the scroll thumb down.
    1185           0 :     ParentLayerCoord yTranslation = -asyncScrollY * ratio;
    1186             : 
    1187             :     // The scroll thumb additionally needs to be translated to compensate for
    1188             :     // the scale applied above. The origin with respect to which the scale is
    1189             :     // applied is the origin of the entire scrollbar, rather than the origin of
    1190             :     // the scroll thumb (meaning, for a vertical scrollbar it's at the top of
    1191             :     // the composition bounds). This means that empty space above the thumb
    1192             :     // is scaled too, effectively translating the thumb. We undo that
    1193             :     // translation here.
    1194             :     // (One can think of the adjustment being done to the translation here as
    1195             :     // a change of basis. We have a method to help with that,
    1196             :     // Matrix4x4::ChangeBasis(), but it wouldn't necessarily make the code
    1197             :     // cleaner in this case).
    1198           0 :     const CSSCoord thumbOrigin = (aMetrics.GetScrollOffset().y * ratio);
    1199           0 :     const CSSCoord thumbOriginScaled = thumbOrigin * yScale;
    1200           0 :     const CSSCoord thumbOriginDelta = thumbOriginScaled - thumbOrigin;
    1201           0 :     const ParentLayerCoord thumbOriginDeltaPL = thumbOriginDelta * effectiveZoom;
    1202           0 :     yTranslation -= thumbOriginDeltaPL;
    1203             : 
    1204           0 :     if (aMetrics.IsRootContent()) {
    1205             :       // Scrollbar for the root are painted at the same resolution as the
    1206             :       // content. Since the coordinate space we apply this transform in includes
    1207             :       // the resolution, we need to adjust for it as well here. Note that in
    1208             :       // another metrics.IsRootContent() hunk below we apply a
    1209             :       // resolution-cancelling transform which ensures the scroll thumb isn't
    1210             :       // actually rendered at a larger scale.
    1211           0 :       yTranslation *= aMetrics.GetPresShellResolution();
    1212             :     }
    1213             : 
    1214           0 :     scrollbarTransform.PostScale(1.f, yScale, 1.f);
    1215           0 :     scrollbarTransform.PostTranslate(0, yTranslation, 0);
    1216             :   }
    1217           0 :   if (aThumbData.mDirection == ScrollDirection::HORIZONTAL) {
    1218             :     // See detailed comments under the VERTICAL case.
    1219             : 
    1220           0 :     const ParentLayerCoord asyncScrollX = asyncTransform._41;
    1221           0 :     const float asyncZoomX = asyncTransform._11;
    1222             : 
    1223           0 :     const float xScale = 1.f / asyncZoomX;
    1224             : 
    1225           0 :     const CSSToParentLayerScale effectiveZoom(aMetrics.GetZoom().xScale * asyncZoomX);
    1226             : 
    1227           0 :     const float ratio = aThumbData.mThumbRatio /
    1228           0 :         (aMetrics.GetPresShellResolution() * asyncZoomX);
    1229           0 :     ParentLayerCoord xTranslation = -asyncScrollX * ratio;
    1230             : 
    1231           0 :     const CSSCoord thumbOrigin = (aMetrics.GetScrollOffset().x * ratio);
    1232           0 :     const CSSCoord thumbOriginScaled = thumbOrigin * xScale;
    1233           0 :     const CSSCoord thumbOriginDelta = thumbOriginScaled - thumbOrigin;
    1234           0 :     const ParentLayerCoord thumbOriginDeltaPL = thumbOriginDelta * effectiveZoom;
    1235           0 :     xTranslation -= thumbOriginDeltaPL;
    1236             : 
    1237           0 :     if (aMetrics.IsRootContent()) {
    1238           0 :       xTranslation *= aMetrics.GetPresShellResolution();
    1239             :     }
    1240             : 
    1241           0 :     scrollbarTransform.PostScale(xScale, 1.f, 1.f);
    1242           0 :     scrollbarTransform.PostTranslate(xTranslation, 0, 0);
    1243             :   }
    1244             : 
    1245             :   LayerToParentLayerMatrix4x4 transform =
    1246           0 :       aCurrentTransform * scrollbarTransform;
    1247             : 
    1248           0 :   AsyncTransformComponentMatrix compensation;
    1249             :   // If the scrollbar layer is for the root then the content's resolution
    1250             :   // applies to the scrollbar as well. Since we don't actually want the scroll
    1251             :   // thumb's size to vary with the zoom (other than its length reflecting the
    1252             :   // fraction of the scrollable length that's in view, which is taken care of
    1253             :   // above), we apply a transform to cancel out this resolution.
    1254           0 :   if (aMetrics.IsRootContent()) {
    1255           0 :     compensation =
    1256           0 :         AsyncTransformComponentMatrix::Scaling(
    1257             :             aMetrics.GetPresShellResolution(),
    1258             :             aMetrics.GetPresShellResolution(),
    1259           0 :             1.0f).Inverse();
    1260             :   }
    1261             :   // If the scrollbar layer is a child of the content it is a scrollbar for,
    1262             :   // then we need to adjust for any async transform (including an overscroll
    1263             :   // transform) on the content. This needs to be cancelled out because layout
    1264             :   // positions and sizes the scrollbar on the assumption that there is no async
    1265             :   // transform, and without this adjustment the scrollbar will end up in the
    1266             :   // wrong place.
    1267             :   //
    1268             :   // Note that since the async transform is applied on top of the content's
    1269             :   // regular transform, we need to make sure to unapply the async transform in
    1270             :   // the same coordinate space. This requires applying the content transform
    1271             :   // and then unapplying it after unapplying the async transform.
    1272           0 :   if (aScrollbarIsDescendant) {
    1273             :     AsyncTransformComponentMatrix overscroll =
    1274           0 :         aApzc->GetOverscrollTransform(AsyncPanZoomController::eForCompositing);
    1275           0 :     Matrix4x4 asyncUntransform = (asyncTransform * overscroll).Inverse().ToUnknownMatrix();
    1276           0 :     Matrix4x4 contentTransform = aScrollableContentTransform;
    1277           0 :     Matrix4x4 contentUntransform = contentTransform.Inverse();
    1278             : 
    1279             :     AsyncTransformComponentMatrix asyncCompensation =
    1280             :         ViewAs<AsyncTransformComponentMatrix>(
    1281             :             contentTransform
    1282           0 :           * asyncUntransform
    1283           0 :           * contentUntransform);
    1284             : 
    1285           0 :     compensation = compensation * asyncCompensation;
    1286             : 
    1287             :     // Pass the async compensation out to the caller so that it can use it
    1288             :     // to transform clip transforms as needed.
    1289           0 :     if (aOutClipTransform) {
    1290           0 :       *aOutClipTransform = asyncCompensation;
    1291             :     }
    1292             :   }
    1293           0 :   transform = transform * compensation;
    1294             : 
    1295           0 :   return transform;
    1296             : }
    1297             : 
    1298             : static LayerMetricsWrapper
    1299           0 : FindScrolledLayerForScrollbar(Layer* aScrollbar, bool* aOutIsAncestor)
    1300             : {
    1301             :   // First check if the scrolled layer is an ancestor of the scrollbar layer.
    1302           0 :   LayerMetricsWrapper root(aScrollbar->Manager()->GetRoot());
    1303           0 :   LayerMetricsWrapper prevAncestor(aScrollbar);
    1304           0 :   LayerMetricsWrapper scrolledLayer;
    1305             : 
    1306           0 :   for (LayerMetricsWrapper ancestor(aScrollbar); ancestor; ancestor = ancestor.GetParent()) {
    1307             :     // Don't walk into remote layer trees; the scrollbar will always be in
    1308             :     // the same layer space.
    1309           0 :     if (ancestor.AsRefLayer()) {
    1310           0 :       root = prevAncestor;
    1311           0 :       break;
    1312             :     }
    1313           0 :     prevAncestor = ancestor;
    1314             : 
    1315           0 :     if (LayerIsScrollbarTarget(ancestor, aScrollbar)) {
    1316           0 :       *aOutIsAncestor = true;
    1317           0 :       return ancestor;
    1318             :     }
    1319             :   }
    1320             : 
    1321             :   // Search the entire layer space of the scrollbar.
    1322           0 :   ForEachNode<ForwardIterator>(
    1323             :       root,
    1324           0 :       [&root, &scrolledLayer, &aScrollbar](LayerMetricsWrapper aLayerMetrics)
    1325           0 :       {
    1326             :         // Do not recurse into RefLayers, since our initial aSubtreeRoot is the
    1327             :         // root (or RefLayer root) of a single layer space to search.
    1328           0 :         if (root != aLayerMetrics && aLayerMetrics.AsRefLayer()) {
    1329           0 :           return TraversalFlag::Skip;
    1330             :         }
    1331           0 :         if (LayerIsScrollbarTarget(aLayerMetrics, aScrollbar)) {
    1332           0 :           scrolledLayer = aLayerMetrics;
    1333           0 :           return TraversalFlag::Abort;
    1334             :         }
    1335           0 :         return TraversalFlag::Continue;
    1336             :       }
    1337           0 :   );
    1338           0 :   return scrolledLayer;
    1339             : }
    1340             : 
    1341             : void
    1342           0 : AsyncCompositionManager::ApplyAsyncTransformToScrollbar(Layer* aLayer)
    1343             : {
    1344             :   // If this layer corresponds to a scrollbar, then there should be a layer that
    1345             :   // is a previous sibling or a parent that has a matching ViewID on its FrameMetrics.
    1346             :   // That is the content that this scrollbar is for. We pick up the transient
    1347             :   // async transform from that layer and use it to update the scrollbar position.
    1348             :   // Note that it is possible that the content layer is no longer there; in
    1349             :   // this case we don't need to do anything because there can't be an async
    1350             :   // transform on the content.
    1351           0 :   bool isAncestor = false;
    1352           0 :   const LayerMetricsWrapper& scrollTarget = FindScrolledLayerForScrollbar(aLayer, &isAncestor);
    1353           0 :   if (scrollTarget) {
    1354           0 :     ApplyAsyncTransformToScrollbarForContent(aLayer, scrollTarget, isAncestor);
    1355             :   }
    1356           0 : }
    1357             : 
    1358             : void
    1359           0 : AsyncCompositionManager::GetFrameUniformity(FrameUniformityData* aOutData)
    1360             : {
    1361           0 :   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    1362           0 :   mLayerTransformRecorder.EndTest(aOutData);
    1363           0 : }
    1364             : 
    1365             : bool
    1366          29 : AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame,
    1367             :                                              TimeDuration aVsyncRate,
    1368             :                                              TransformsToSkip aSkip)
    1369             : {
    1370          58 :   AUTO_PROFILER_LABEL("AsyncCompositionManager::TransformShadowTree", GRAPHICS);
    1371             : 
    1372          29 :   Layer* root = mLayerManager->GetRoot();
    1373          29 :   if (!root) {
    1374           0 :     return false;
    1375             :   }
    1376             : 
    1377             :   CompositorAnimationStorage* storage =
    1378          29 :     mCompositorBridge->GetAnimationStorage();
    1379             :   // First, compute and set the shadow transforms from OMT animations.
    1380             :   // NB: we must sample animations *before* sampling pan/zoom
    1381             :   // transforms.
    1382             :   // Use a previous vsync time to make main thread animations and compositor
    1383             :   // more in sync with each other.
    1384             :   // On the initial frame we use aVsyncTimestamp here so the timestamp on the
    1385             :   // second frame are the same as the initial frame, but it does not matter.
    1386          29 :   uint64_t layerAreaAnimated = 0;
    1387             :   AnimationProcessTypes animationProcess =
    1388             :     SampleAnimations(root,
    1389             :                      storage,
    1390          29 :                      !mPreviousFrameTimeStamp.IsNull() ?
    1391             :                        mPreviousFrameTimeStamp : aCurrentFrame,
    1392          29 :                      &layerAreaAnimated);
    1393          29 :   bool wantNextFrame = (animationProcess != AnimationProcessTypes::eNone);
    1394             : 
    1395          29 :   mAnimationMetricsTracker.UpdateAnimationInProgress(
    1396          58 :     animationProcess, layerAreaAnimated, aVsyncRate);
    1397             : 
    1398          29 :   if (!wantNextFrame) {
    1399             :     // Clean up the CompositorAnimationStorage because
    1400             :     // there are no active animations running
    1401          29 :     storage->Clear();
    1402             :   }
    1403             : 
    1404             :   // Advance animations to the next expected vsync timestamp, if we can
    1405             :   // get it.
    1406          29 :   TimeStamp nextFrame = aCurrentFrame;
    1407             : 
    1408          29 :   MOZ_ASSERT(aVsyncRate != TimeDuration::Forever());
    1409          29 :   if (aVsyncRate != TimeDuration::Forever()) {
    1410          29 :     nextFrame += aVsyncRate;
    1411             :   }
    1412             : 
    1413             : #if defined(MOZ_WIDGET_ANDROID)
    1414             :   Compositor* compositor = mLayerManager->GetCompositor();
    1415             :   if (CompositorBridgeParent* bridge = compositor->GetCompositorBridgeParent()) {
    1416             :     AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
    1417             :     MOZ_ASSERT(animator);
    1418             :     wantNextFrame |= animator->UpdateAnimation(nextFrame);
    1419             :   }
    1420             : #endif // defined(MOZ_WIDGET_ANDROID)
    1421             : 
    1422             :   // Reset the previous time stamp if we don't already have any running
    1423             :   // animations to avoid using the time which is far behind for newly
    1424             :   // started animations.
    1425          29 :   mPreviousFrameTimeStamp = wantNextFrame ? aCurrentFrame : TimeStamp();
    1426             : 
    1427          29 :   if (!(aSkip & TransformsToSkip::APZ)) {
    1428             :     // FIXME/bug 775437: unify this interface with the ~native-fennec
    1429             :     // derived code
    1430             :     //
    1431             :     // Attempt to apply an async content transform to any layer that has
    1432             :     // an async pan zoom controller (which means that it is rendered
    1433             :     // async using Gecko). If this fails, fall back to transforming the
    1434             :     // primary scrollable layer.  "Failing" here means that we don't
    1435             :     // find a frame that is async scrollable.  Note that the fallback
    1436             :     // code also includes Fennec which is rendered async.  Fennec uses
    1437             :     // its own platform-specific async rendering that is done partially
    1438             :     // in Gecko and partially in Java.
    1439          29 :     bool foundRoot = false;
    1440          29 :     if (ApplyAsyncContentTransformToTree(root, &foundRoot)) {
    1441             : #if defined(MOZ_WIDGET_ANDROID)
    1442             :       MOZ_ASSERT(foundRoot);
    1443             :       if (foundRoot && mFixedLayerMargins != ScreenMargin()) {
    1444             :         MoveScrollbarForLayerMargin(root, mRootScrollableId, mFixedLayerMargins);
    1445             :       }
    1446             : #endif
    1447             :     }
    1448             : 
    1449          29 :     bool apzAnimating = SampleAPZAnimations(LayerMetricsWrapper(root), nextFrame);
    1450          29 :     mAnimationMetricsTracker.UpdateApzAnimationInProgress(apzAnimating, aVsyncRate);
    1451          29 :     wantNextFrame |= apzAnimating;
    1452             :   }
    1453             : 
    1454          29 :   HostLayer* rootComposite = root->AsHostLayer();
    1455             : 
    1456          29 :   gfx::Matrix4x4 trans = rootComposite->GetShadowBaseTransform();
    1457          29 :   trans *= gfx::Matrix4x4::From2D(mWorldTransform);
    1458          29 :   rootComposite->SetShadowBaseTransform(trans);
    1459             : 
    1460          29 :   if (gfxPrefs::CollectScrollTransforms()) {
    1461           0 :     RecordShadowTransforms(root);
    1462             :   }
    1463             : 
    1464          29 :   return wantNextFrame;
    1465             : }
    1466             : 
    1467             : #if defined(MOZ_WIDGET_ANDROID)
    1468             : void
    1469             : AsyncCompositionManager::SetFixedLayerMargins(ScreenIntCoord aTop, ScreenIntCoord aBottom)
    1470             : {
    1471             :   mFixedLayerMargins.top = aTop;
    1472             :   mFixedLayerMargins.bottom = aBottom;
    1473             : }
    1474             : #endif // defined(MOZ_WIDGET_ANDROID)
    1475             : 
    1476             : } // namespace layers
    1477             : } // namespace mozilla

Generated by: LCOV version 1.13