gfx/layers/composite/AsyncCompositionManager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/layers/composite/AsyncCompositionManager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,948 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set sw=2 ts=2 et tw=80 : */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "mozilla/layers/AsyncCompositionManager.h"
    1.11 +#include <stdint.h>                     // for uint32_t
    1.12 +#include "AnimationCommon.h"            // for ComputedTimingFunction
    1.13 +#include "CompositorParent.h"           // for CompositorParent, etc
    1.14 +#include "FrameMetrics.h"               // for FrameMetrics
    1.15 +#include "LayerManagerComposite.h"      // for LayerManagerComposite, etc
    1.16 +#include "Layers.h"                     // for Layer, ContainerLayer, etc
    1.17 +#include "gfxPoint.h"                   // for gfxPoint, gfxSize
    1.18 +#include "gfxPoint3D.h"                 // for gfxPoint3D
    1.19 +#include "mozilla/WidgetUtils.h"        // for ComputeTransformForRotation
    1.20 +#include "mozilla/gfx/BaseRect.h"       // for BaseRect
    1.21 +#include "mozilla/gfx/Point.h"          // for RoundedToInt, PointTyped
    1.22 +#include "mozilla/gfx/Rect.h"           // for RoundedToInt, RectTyped
    1.23 +#include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
    1.24 +#include "mozilla/layers/AsyncPanZoomController.h"
    1.25 +#include "mozilla/layers/Compositor.h"  // for Compositor
    1.26 +#include "nsAnimationManager.h"         // for ElementAnimations
    1.27 +#include "nsCSSPropList.h"
    1.28 +#include "nsCoord.h"                    // for NSAppUnitsToFloatPixels, etc
    1.29 +#include "nsDebug.h"                    // for NS_ASSERTION, etc
    1.30 +#include "nsDeviceContext.h"            // for nsDeviceContext
    1.31 +#include "nsDisplayList.h"              // for nsDisplayTransform, etc
    1.32 +#include "nsMathUtils.h"                // for NS_round
    1.33 +#include "nsPoint.h"                    // for nsPoint
    1.34 +#include "nsRect.h"                     // for nsIntRect
    1.35 +#include "nsRegion.h"                   // for nsIntRegion
    1.36 +#include "nsStyleAnimation.h"           // for nsStyleAnimation::Value, etc
    1.37 +#include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
    1.38 +#include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
    1.39 +#if defined(MOZ_WIDGET_ANDROID)
    1.40 +# include <android/log.h>
    1.41 +# include "AndroidBridge.h"
    1.42 +#endif
    1.43 +#include "GeckoProfiler.h"
    1.44 +
    1.45 +struct nsCSSValueSharedList;
    1.46 +
    1.47 +using namespace mozilla::dom;
    1.48 +using namespace mozilla::gfx;
    1.49 +
    1.50 +namespace mozilla {
    1.51 +namespace layers {
    1.52 +
    1.53 +enum Op { Resolve, Detach };
    1.54 +
    1.55 +static bool
    1.56 +IsSameDimension(ScreenOrientation o1, ScreenOrientation o2)
    1.57 +{
    1.58 +  bool isO1portrait = (o1 == eScreenOrientation_PortraitPrimary || o1 == eScreenOrientation_PortraitSecondary);
    1.59 +  bool isO2portrait = (o2 == eScreenOrientation_PortraitPrimary || o2 == eScreenOrientation_PortraitSecondary);
    1.60 +  return !(isO1portrait ^ isO2portrait);
    1.61 +}
    1.62 +
    1.63 +static bool
    1.64 +ContentMightReflowOnOrientationChange(const nsIntRect& rect)
    1.65 +{
    1.66 +  return rect.width != rect.height;
    1.67 +}
    1.68 +
    1.69 +template<Op OP>
    1.70 +static void
    1.71 +WalkTheTree(Layer* aLayer,
    1.72 +            bool& aReady,
    1.73 +            const TargetConfig& aTargetConfig)
    1.74 +{
    1.75 +  if (RefLayer* ref = aLayer->AsRefLayer()) {
    1.76 +    if (const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(ref->GetReferentId())) {
    1.77 +      if (Layer* referent = state->mRoot) {
    1.78 +        if (!ref->GetVisibleRegion().IsEmpty()) {
    1.79 +          ScreenOrientation chromeOrientation = aTargetConfig.orientation();
    1.80 +          ScreenOrientation contentOrientation = state->mTargetConfig.orientation();
    1.81 +          if (!IsSameDimension(chromeOrientation, contentOrientation) &&
    1.82 +              ContentMightReflowOnOrientationChange(aTargetConfig.clientBounds())) {
    1.83 +            aReady = false;
    1.84 +          }
    1.85 +        }
    1.86 +
    1.87 +        if (OP == Resolve) {
    1.88 +          ref->ConnectReferentLayer(referent);
    1.89 +        } else {
    1.90 +          ref->DetachReferentLayer(referent);
    1.91 +        }
    1.92 +      }
    1.93 +    }
    1.94 +  }
    1.95 +  for (Layer* child = aLayer->GetFirstChild();
    1.96 +       child; child = child->GetNextSibling()) {
    1.97 +    WalkTheTree<OP>(child, aReady, aTargetConfig);
    1.98 +  }
    1.99 +}
   1.100 +
   1.101 +void
   1.102 +AsyncCompositionManager::ResolveRefLayers()
   1.103 +{
   1.104 +  if (!mLayerManager->GetRoot()) {
   1.105 +    return;
   1.106 +  }
   1.107 +
   1.108 +  mReadyForCompose = true;
   1.109 +  WalkTheTree<Resolve>(mLayerManager->GetRoot(),
   1.110 +                       mReadyForCompose,
   1.111 +                       mTargetConfig);
   1.112 +}
   1.113 +
   1.114 +void
   1.115 +AsyncCompositionManager::DetachRefLayers()
   1.116 +{
   1.117 +  if (!mLayerManager->GetRoot()) {
   1.118 +    return;
   1.119 +  }
   1.120 +  WalkTheTree<Detach>(mLayerManager->GetRoot(),
   1.121 +                      mReadyForCompose,
   1.122 +                      mTargetConfig);
   1.123 +}
   1.124 +
   1.125 +void
   1.126 +AsyncCompositionManager::ComputeRotation()
   1.127 +{
   1.128 +  if (!mTargetConfig.naturalBounds().IsEmpty()) {
   1.129 +    mLayerManager->SetWorldTransform(
   1.130 +      ComputeTransformForRotation(mTargetConfig.naturalBounds(),
   1.131 +                                  mTargetConfig.rotation()));
   1.132 +  }
   1.133 +}
   1.134 +
   1.135 +static bool
   1.136 +GetBaseTransform2D(Layer* aLayer, Matrix* aTransform)
   1.137 +{
   1.138 +  // Start with the animated transform if there is one
   1.139 +  return (aLayer->AsLayerComposite()->GetShadowTransformSetByAnimation() ?
   1.140 +          aLayer->GetLocalTransform() : aLayer->GetTransform()).Is2D(aTransform);
   1.141 +}
   1.142 +
   1.143 +static void
   1.144 +TranslateShadowLayer2D(Layer* aLayer,
   1.145 +                       const gfxPoint& aTranslation)
   1.146 +{
   1.147 +  Matrix layerTransform;
   1.148 +  if (!GetBaseTransform2D(aLayer, &layerTransform)) {
   1.149 +    return;
   1.150 +  }
   1.151 +
   1.152 +  // Apply the 2D translation to the layer transform.
   1.153 +  layerTransform._31 += aTranslation.x;
   1.154 +  layerTransform._32 += aTranslation.y;
   1.155 +
   1.156 +  // The transform already takes the resolution scale into account.  Since we
   1.157 +  // will apply the resolution scale again when computing the effective
   1.158 +  // transform, we must apply the inverse resolution scale here.
   1.159 +  Matrix4x4 layerTransform3D = Matrix4x4::From2D(layerTransform);
   1.160 +  if (ContainerLayer* c = aLayer->AsContainerLayer()) {
   1.161 +    layerTransform3D.Scale(1.0f/c->GetPreXScale(),
   1.162 +                           1.0f/c->GetPreYScale(),
   1.163 +                           1);
   1.164 +  }
   1.165 +  layerTransform3D = layerTransform3D *
   1.166 +    Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
   1.167 +                      1.0f/aLayer->GetPostYScale(),
   1.168 +                      1);
   1.169 +
   1.170 +  LayerComposite* layerComposite = aLayer->AsLayerComposite();
   1.171 +  layerComposite->SetShadowTransform(layerTransform3D);
   1.172 +  layerComposite->SetShadowTransformSetByAnimation(false);
   1.173 +
   1.174 +  const nsIntRect* clipRect = aLayer->GetClipRect();
   1.175 +  if (clipRect) {
   1.176 +    nsIntRect transformedClipRect(*clipRect);
   1.177 +    transformedClipRect.MoveBy(aTranslation.x, aTranslation.y);
   1.178 +    layerComposite->SetShadowClipRect(&transformedClipRect);
   1.179 +  }
   1.180 +}
   1.181 +
   1.182 +static bool
   1.183 +AccumulateLayerTransforms2D(Layer* aLayer,
   1.184 +                            Layer* aAncestor,
   1.185 +                            Matrix& aMatrix)
   1.186 +{
   1.187 +  // Accumulate the transforms between this layer and the subtree root layer.
   1.188 +  for (Layer* l = aLayer; l && l != aAncestor; l = l->GetParent()) {
   1.189 +    Matrix l2D;
   1.190 +    if (!GetBaseTransform2D(l, &l2D)) {
   1.191 +      return false;
   1.192 +    }
   1.193 +    aMatrix *= l2D;
   1.194 +  }
   1.195 +
   1.196 +  return true;
   1.197 +}
   1.198 +
   1.199 +static LayerPoint
   1.200 +GetLayerFixedMarginsOffset(Layer* aLayer,
   1.201 +                           const LayerMargin& aFixedLayerMargins)
   1.202 +{
   1.203 +  // Work out the necessary translation, in root scrollable layer space.
   1.204 +  // Because fixed layer margins are stored relative to the root scrollable
   1.205 +  // layer, we can just take the difference between these values.
   1.206 +  LayerPoint translation;
   1.207 +  const LayerPoint& anchor = aLayer->GetFixedPositionAnchor();
   1.208 +  const LayerMargin& fixedMargins = aLayer->GetFixedPositionMargins();
   1.209 +
   1.210 +  if (fixedMargins.left >= 0) {
   1.211 +    if (anchor.x > 0) {
   1.212 +      translation.x -= aFixedLayerMargins.right - fixedMargins.right;
   1.213 +    } else {
   1.214 +      translation.x += aFixedLayerMargins.left - fixedMargins.left;
   1.215 +    }
   1.216 +  }
   1.217 +
   1.218 +  if (fixedMargins.top >= 0) {
   1.219 +    if (anchor.y > 0) {
   1.220 +      translation.y -= aFixedLayerMargins.bottom - fixedMargins.bottom;
   1.221 +    } else {
   1.222 +      translation.y += aFixedLayerMargins.top - fixedMargins.top;
   1.223 +    }
   1.224 +  }
   1.225 +
   1.226 +  return translation;
   1.227 +}
   1.228 +
   1.229 +static gfxFloat
   1.230 +IntervalOverlap(gfxFloat aTranslation, gfxFloat aMin, gfxFloat aMax)
   1.231 +{
   1.232 +  // Determine the amount of overlap between the 1D vector |aTranslation|
   1.233 +  // and the interval [aMin, aMax].
   1.234 +  if (aTranslation > 0) {
   1.235 +    return std::max(0.0, std::min(aMax, aTranslation) - std::max(aMin, 0.0));
   1.236 +  } else {
   1.237 +    return std::min(0.0, std::max(aMin, aTranslation) - std::min(aMax, 0.0));
   1.238 +  }
   1.239 +}
   1.240 +
   1.241 +void
   1.242 +AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
   1.243 +                                                   Layer* aTransformedSubtreeRoot,
   1.244 +                                                   const Matrix4x4& aPreviousTransformForRoot,
   1.245 +                                                   const LayerMargin& aFixedLayerMargins)
   1.246 +{
   1.247 +  bool isRootFixed = aLayer->GetIsFixedPosition() &&
   1.248 +    !aLayer->GetParent()->GetIsFixedPosition();
   1.249 +  bool isStickyForSubtree = aLayer->GetIsStickyPosition() &&
   1.250 +    aTransformedSubtreeRoot->AsContainerLayer() &&
   1.251 +    aLayer->GetStickyScrollContainerId() ==
   1.252 +      aTransformedSubtreeRoot->AsContainerLayer()->GetFrameMetrics().GetScrollId();
   1.253 +  if (aLayer != aTransformedSubtreeRoot && (isRootFixed || isStickyForSubtree)) {
   1.254 +    // Insert a translation so that the position of the anchor point is the same
   1.255 +    // before and after the change to the transform of aTransformedSubtreeRoot.
   1.256 +    // This currently only works for fixed layers with 2D transforms.
   1.257 +
   1.258 +    // Accumulate the transforms between this layer and the subtree root layer.
   1.259 +    Matrix ancestorTransform;
   1.260 +    if (!AccumulateLayerTransforms2D(aLayer->GetParent(), aTransformedSubtreeRoot,
   1.261 +                                     ancestorTransform)) {
   1.262 +      return;
   1.263 +    }
   1.264 +
   1.265 +    Matrix oldRootTransform;
   1.266 +    Matrix newRootTransform;
   1.267 +    if (!aPreviousTransformForRoot.Is2D(&oldRootTransform) ||
   1.268 +        !aTransformedSubtreeRoot->GetLocalTransform().Is2D(&newRootTransform)) {
   1.269 +      return;
   1.270 +    }
   1.271 +
   1.272 +    // Calculate the cumulative transforms between the subtree root with the
   1.273 +    // old transform and the current transform.
   1.274 +    Matrix oldCumulativeTransform = ancestorTransform * oldRootTransform;
   1.275 +    Matrix newCumulativeTransform = ancestorTransform * newRootTransform;
   1.276 +    if (newCumulativeTransform.IsSingular()) {
   1.277 +      return;
   1.278 +    }
   1.279 +    Matrix newCumulativeTransformInverse = newCumulativeTransform;
   1.280 +    newCumulativeTransformInverse.Invert();
   1.281 +
   1.282 +    // Now work out the translation necessary to make sure the layer doesn't
   1.283 +    // move given the new sub-tree root transform.
   1.284 +    Matrix layerTransform;
   1.285 +    if (!GetBaseTransform2D(aLayer, &layerTransform)) {
   1.286 +      return;
   1.287 +    }
   1.288 +
   1.289 +    // Calculate any offset necessary, in previous transform sub-tree root
   1.290 +    // space. This is used to make sure fixed position content respects
   1.291 +    // content document fixed position margins.
   1.292 +    LayerPoint offsetInOldSubtreeLayerSpace = GetLayerFixedMarginsOffset(aLayer, aFixedLayerMargins);
   1.293 +
   1.294 +    // Add the above offset to the anchor point so we can offset the layer by
   1.295 +    // and amount that's specified in old subtree layer space.
   1.296 +    const LayerPoint& anchorInOldSubtreeLayerSpace = aLayer->GetFixedPositionAnchor();
   1.297 +    LayerPoint offsetAnchorInOldSubtreeLayerSpace = anchorInOldSubtreeLayerSpace + offsetInOldSubtreeLayerSpace;
   1.298 +
   1.299 +    // Add the local layer transform to the two points to make the equation
   1.300 +    // below this section more convenient.
   1.301 +    Point anchor(anchorInOldSubtreeLayerSpace.x, anchorInOldSubtreeLayerSpace.y);
   1.302 +    Point offsetAnchor(offsetAnchorInOldSubtreeLayerSpace.x, offsetAnchorInOldSubtreeLayerSpace.y);
   1.303 +    Point locallyTransformedAnchor = layerTransform * anchor;
   1.304 +    Point locallyTransformedOffsetAnchor = layerTransform * offsetAnchor;
   1.305 +
   1.306 +    // Transforming the locallyTransformedAnchor by oldCumulativeTransform
   1.307 +    // returns the layer's anchor point relative to the parent of
   1.308 +    // aTransformedSubtreeRoot, before the new transform was applied.
   1.309 +    // Then, applying newCumulativeTransformInverse maps that point relative
   1.310 +    // to the layer's parent, which is the same coordinate space as
   1.311 +    // locallyTransformedAnchor again, allowing us to subtract them and find
   1.312 +    // out the offset necessary to make sure the layer stays stationary.
   1.313 +    Point oldAnchorPositionInNewSpace =
   1.314 +      newCumulativeTransformInverse * (oldCumulativeTransform * locallyTransformedOffsetAnchor);
   1.315 +    Point translation = oldAnchorPositionInNewSpace - locallyTransformedAnchor;
   1.316 +
   1.317 +    if (aLayer->GetIsStickyPosition()) {
   1.318 +      // For sticky positioned layers, the difference between the two rectangles
   1.319 +      // defines a pair of translation intervals in each dimension through which
   1.320 +      // the layer should not move relative to the scroll container. To
   1.321 +      // accomplish this, we limit each dimension of the |translation| to that
   1.322 +      // part of it which overlaps those intervals.
   1.323 +      const LayerRect& stickyOuter = aLayer->GetStickyScrollRangeOuter();
   1.324 +      const LayerRect& stickyInner = aLayer->GetStickyScrollRangeInner();
   1.325 +
   1.326 +      translation.y = IntervalOverlap(translation.y, stickyOuter.y, stickyOuter.YMost()) -
   1.327 +                      IntervalOverlap(translation.y, stickyInner.y, stickyInner.YMost());
   1.328 +      translation.x = IntervalOverlap(translation.x, stickyOuter.x, stickyOuter.XMost()) -
   1.329 +                      IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost());
   1.330 +    }
   1.331 +
   1.332 +    // Finally, apply the 2D translation to the layer transform.
   1.333 +    TranslateShadowLayer2D(aLayer, ThebesPoint(translation));
   1.334 +
   1.335 +    // The transform has now been applied, so there's no need to iterate over
   1.336 +    // child layers.
   1.337 +    return;
   1.338 +  }
   1.339 +
   1.340 +  // Fixed layers are relative to their nearest scrollable layer, so when we
   1.341 +  // encounter a scrollable layer, reset the transform to that layer and remove
   1.342 +  // the fixed margins.
   1.343 +  if (aLayer->AsContainerLayer() &&
   1.344 +      aLayer->AsContainerLayer()->GetFrameMetrics().IsScrollable() &&
   1.345 +      aLayer != aTransformedSubtreeRoot) {
   1.346 +    AlignFixedAndStickyLayers(aLayer, aLayer, aLayer->GetTransform(), LayerMargin(0, 0, 0, 0));
   1.347 +    return;
   1.348 +  }
   1.349 +
   1.350 +  for (Layer* child = aLayer->GetFirstChild();
   1.351 +       child; child = child->GetNextSibling()) {
   1.352 +    AlignFixedAndStickyLayers(child, aTransformedSubtreeRoot,
   1.353 +                              aPreviousTransformForRoot, aFixedLayerMargins);
   1.354 +  }
   1.355 +}
   1.356 +
   1.357 +static void
   1.358 +SampleValue(float aPortion, Animation& aAnimation, nsStyleAnimation::Value& aStart,
   1.359 +            nsStyleAnimation::Value& aEnd, Animatable* aValue)
   1.360 +{
   1.361 +  nsStyleAnimation::Value interpolatedValue;
   1.362 +  NS_ASSERTION(aStart.GetUnit() == aEnd.GetUnit() ||
   1.363 +               aStart.GetUnit() == nsStyleAnimation::eUnit_None ||
   1.364 +               aEnd.GetUnit() == nsStyleAnimation::eUnit_None, "Must have same unit");
   1.365 +  nsStyleAnimation::Interpolate(aAnimation.property(), aStart, aEnd,
   1.366 +                                aPortion, interpolatedValue);
   1.367 +  if (aAnimation.property() == eCSSProperty_opacity) {
   1.368 +    *aValue = interpolatedValue.GetFloatValue();
   1.369 +    return;
   1.370 +  }
   1.371 +
   1.372 +  nsCSSValueSharedList* interpolatedList =
   1.373 +    interpolatedValue.GetCSSValueSharedListValue();
   1.374 +
   1.375 +  TransformData& data = aAnimation.data().get_TransformData();
   1.376 +  nsPoint origin = data.origin();
   1.377 +  // we expect all our transform data to arrive in css pixels, so here we must
   1.378 +  // adjust to dev pixels.
   1.379 +  double cssPerDev = double(nsDeviceContext::AppUnitsPerCSSPixel())
   1.380 +                     / double(data.appUnitsPerDevPixel());
   1.381 +  gfxPoint3D transformOrigin = data.transformOrigin();
   1.382 +  transformOrigin.x = transformOrigin.x * cssPerDev;
   1.383 +  transformOrigin.y = transformOrigin.y * cssPerDev;
   1.384 +  gfxPoint3D perspectiveOrigin = data.perspectiveOrigin();
   1.385 +  perspectiveOrigin.x = perspectiveOrigin.x * cssPerDev;
   1.386 +  perspectiveOrigin.y = perspectiveOrigin.y * cssPerDev;
   1.387 +  nsDisplayTransform::FrameTransformProperties props(interpolatedList,
   1.388 +                                                     transformOrigin,
   1.389 +                                                     perspectiveOrigin,
   1.390 +                                                     data.perspective());
   1.391 +  gfx3DMatrix transform =
   1.392 +    nsDisplayTransform::GetResultingTransformMatrix(props, origin,
   1.393 +                                                    data.appUnitsPerDevPixel(),
   1.394 +                                                    &data.bounds());
   1.395 +  gfxPoint3D scaledOrigin =
   1.396 +    gfxPoint3D(NS_round(NSAppUnitsToFloatPixels(origin.x, data.appUnitsPerDevPixel())),
   1.397 +               NS_round(NSAppUnitsToFloatPixels(origin.y, data.appUnitsPerDevPixel())),
   1.398 +               0.0f);
   1.399 +
   1.400 +  transform.Translate(scaledOrigin);
   1.401 +
   1.402 +  InfallibleTArray<TransformFunction> functions;
   1.403 +  Matrix4x4 realTransform;
   1.404 +  ToMatrix4x4(transform, realTransform);
   1.405 +  functions.AppendElement(TransformMatrix(realTransform));
   1.406 +  *aValue = functions;
   1.407 +}
   1.408 +
   1.409 +static bool
   1.410 +SampleAnimations(Layer* aLayer, TimeStamp aPoint)
   1.411 +{
   1.412 +  AnimationArray& animations = aLayer->GetAnimations();
   1.413 +  InfallibleTArray<AnimData>& animationData = aLayer->GetAnimationData();
   1.414 +
   1.415 +  bool activeAnimations = false;
   1.416 +
   1.417 +  for (uint32_t i = animations.Length(); i-- !=0; ) {
   1.418 +    Animation& animation = animations[i];
   1.419 +    AnimData& animData = animationData[i];
   1.420 +
   1.421 +    activeAnimations = true;
   1.422 +
   1.423 +    TimeDuration elapsedDuration = aPoint - animation.startTime();
   1.424 +    // Skip animations that are yet to start.
   1.425 +    //
   1.426 +    // Currently, this should only happen when the refresh driver is under test
   1.427 +    // control and is made to produce a time in the past or is restored from
   1.428 +    // test control causing it to jump backwards in time.
   1.429 +    //
   1.430 +    // Since activeAnimations is true, this could mean we keep compositing
   1.431 +    // unnecessarily during the delay, but so long as this only happens while
   1.432 +    // the refresh driver is under test control that should be ok.
   1.433 +    if (elapsedDuration.ToSeconds() < 0) {
   1.434 +      continue;
   1.435 +    }
   1.436 +
   1.437 +    double numIterations = animation.numIterations() != -1 ?
   1.438 +      animation.numIterations() : NS_IEEEPositiveInfinity();
   1.439 +    double positionInIteration =
   1.440 +      ElementAnimations::GetPositionInIteration(elapsedDuration,
   1.441 +                                                animation.duration(),
   1.442 +                                                numIterations,
   1.443 +                                                animation.direction());
   1.444 +
   1.445 +    NS_ABORT_IF_FALSE(0.0 <= positionInIteration &&
   1.446 +                      positionInIteration <= 1.0,
   1.447 +                      "position should be in [0-1]");
   1.448 +
   1.449 +    int segmentIndex = 0;
   1.450 +    AnimationSegment* segment = animation.segments().Elements();
   1.451 +    while (segment->endPortion() < positionInIteration) {
   1.452 +      ++segment;
   1.453 +      ++segmentIndex;
   1.454 +    }
   1.455 +
   1.456 +    double positionInSegment = (positionInIteration - segment->startPortion()) /
   1.457 +                                 (segment->endPortion() - segment->startPortion());
   1.458 +
   1.459 +    double portion = animData.mFunctions[segmentIndex]->GetValue(positionInSegment);
   1.460 +
   1.461 +    // interpolate the property
   1.462 +    Animatable interpolatedValue;
   1.463 +    SampleValue(portion, animation, animData.mStartValues[segmentIndex],
   1.464 +                animData.mEndValues[segmentIndex], &interpolatedValue);
   1.465 +    LayerComposite* layerComposite = aLayer->AsLayerComposite();
   1.466 +    switch (animation.property()) {
   1.467 +    case eCSSProperty_opacity:
   1.468 +    {
   1.469 +      layerComposite->SetShadowOpacity(interpolatedValue.get_float());
   1.470 +      break;
   1.471 +    }
   1.472 +    case eCSSProperty_transform:
   1.473 +    {
   1.474 +      Matrix4x4 matrix = interpolatedValue.get_ArrayOfTransformFunction()[0].get_TransformMatrix().value();
   1.475 +      if (ContainerLayer* c = aLayer->AsContainerLayer()) {
   1.476 +        matrix = matrix * Matrix4x4().Scale(c->GetInheritedXScale(),
   1.477 +                                            c->GetInheritedYScale(),
   1.478 +                                            1);
   1.479 +      }
   1.480 +      layerComposite->SetShadowTransform(matrix);
   1.481 +      layerComposite->SetShadowTransformSetByAnimation(true);
   1.482 +      break;
   1.483 +    }
   1.484 +    default:
   1.485 +      NS_WARNING("Unhandled animated property");
   1.486 +    }
   1.487 +  }
   1.488 +
   1.489 +  for (Layer* child = aLayer->GetFirstChild(); child;
   1.490 +       child = child->GetNextSibling()) {
   1.491 +    activeAnimations |= SampleAnimations(child, aPoint);
   1.492 +  }
   1.493 +
   1.494 +  return activeAnimations;
   1.495 +}
   1.496 +
   1.497 +bool
   1.498 +AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame,
   1.499 +                                                          Layer *aLayer,
   1.500 +                                                          bool* aWantNextFrame)
   1.501 +{
   1.502 +  bool appliedTransform = false;
   1.503 +  for (Layer* child = aLayer->GetFirstChild();
   1.504 +      child; child = child->GetNextSibling()) {
   1.505 +    appliedTransform |=
   1.506 +      ApplyAsyncContentTransformToTree(aCurrentFrame, child, aWantNextFrame);
   1.507 +  }
   1.508 +
   1.509 +  ContainerLayer* container = aLayer->AsContainerLayer();
   1.510 +  if (!container) {
   1.511 +    return appliedTransform;
   1.512 +  }
   1.513 +
   1.514 +  if (AsyncPanZoomController* controller = container->GetAsyncPanZoomController()) {
   1.515 +    LayerComposite* layerComposite = aLayer->AsLayerComposite();
   1.516 +    Matrix4x4 oldTransform = aLayer->GetTransform();
   1.517 +
   1.518 +    ViewTransform treeTransform;
   1.519 +    ScreenPoint scrollOffset;
   1.520 +    *aWantNextFrame |=
   1.521 +      controller->SampleContentTransformForFrame(aCurrentFrame,
   1.522 +                                                 &treeTransform,
   1.523 +                                                 scrollOffset);
   1.524 +
   1.525 +    const FrameMetrics& metrics = container->GetFrameMetrics();
   1.526 +    CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
   1.527 +    CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ?
   1.528 +                        metrics.mDisplayPort : metrics.mCriticalDisplayPort);
   1.529 +    LayerMargin fixedLayerMargins(0, 0, 0, 0);
   1.530 +    ScreenPoint offset(0, 0);
   1.531 +    SyncFrameMetrics(scrollOffset, treeTransform.mScale.scale, metrics.mScrollableRect,
   1.532 +                     mLayersUpdated, displayPort, paintScale,
   1.533 +                     mIsFirstPaint, fixedLayerMargins, offset);
   1.534 +
   1.535 +    mIsFirstPaint = false;
   1.536 +    mLayersUpdated = false;
   1.537 +
   1.538 +    // Apply the render offset
   1.539 +    mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
   1.540 +
   1.541 +    Matrix4x4 transform;
   1.542 +    ToMatrix4x4(gfx3DMatrix(treeTransform), transform);
   1.543 +    transform = transform * aLayer->GetTransform();
   1.544 +
   1.545 +    // GetTransform already takes the pre- and post-scale into account.  Since we
   1.546 +    // will apply the pre- and post-scale again when computing the effective
   1.547 +    // transform, we must apply the inverses here.
   1.548 +    transform.Scale(1.0f/container->GetPreXScale(),
   1.549 +                    1.0f/container->GetPreYScale(),
   1.550 +                    1);
   1.551 +    transform = transform * Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
   1.552 +                                              1.0f/aLayer->GetPostYScale(),
   1.553 +                                              1);
   1.554 +    layerComposite->SetShadowTransform(transform);
   1.555 +    NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
   1.556 +                 "overwriting animated transform!");
   1.557 +
   1.558 +    // Apply resolution scaling to the old transform - the layer tree as it is
   1.559 +    // doesn't have the necessary transform to display correctly.
   1.560 +    LayoutDeviceToLayerScale resolution = metrics.mCumulativeResolution;
   1.561 +    oldTransform.Scale(resolution.scale, resolution.scale, 1);
   1.562 +
   1.563 +    AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform, fixedLayerMargins);
   1.564 +
   1.565 +    appliedTransform = true;
   1.566 +  }
   1.567 +
   1.568 +  if (container->GetScrollbarDirection() != Layer::NONE) {
   1.569 +    ApplyAsyncTransformToScrollbar(aCurrentFrame, container);
   1.570 +  }
   1.571 +  return appliedTransform;
   1.572 +}
   1.573 +
   1.574 +static bool
   1.575 +LayerHasNonContainerDescendants(ContainerLayer* aContainer)
   1.576 +{
   1.577 +  for (Layer* child = aContainer->GetFirstChild();
   1.578 +       child; child = child->GetNextSibling()) {
   1.579 +    ContainerLayer* container = child->AsContainerLayer();
   1.580 +    if (!container || LayerHasNonContainerDescendants(container)) {
   1.581 +      return true;
   1.582 +    }
   1.583 +  }
   1.584 +
   1.585 +  return false;
   1.586 +}
   1.587 +
   1.588 +static bool
   1.589 +LayerIsContainerForScrollbarTarget(Layer* aTarget, ContainerLayer* aScrollbar)
   1.590 +{
   1.591 +  if (!aTarget->AsContainerLayer()) {
   1.592 +    return false;
   1.593 +  }
   1.594 +  AsyncPanZoomController* apzc = aTarget->AsContainerLayer()->GetAsyncPanZoomController();
   1.595 +  if (!apzc) {
   1.596 +    return false;
   1.597 +  }
   1.598 +  const FrameMetrics& metrics = aTarget->AsContainerLayer()->GetFrameMetrics();
   1.599 +  if (metrics.GetScrollId() != aScrollbar->GetScrollbarTargetContainerId()) {
   1.600 +    return false;
   1.601 +  }
   1.602 +  return true;
   1.603 +}
   1.604 +
   1.605 +static void
   1.606 +ApplyAsyncTransformToScrollbarForContent(TimeStamp aCurrentFrame, ContainerLayer* aScrollbar,
   1.607 +                                         Layer* aContent, bool aScrollbarIsChild)
   1.608 +{
   1.609 +  ContainerLayer* content = aContent->AsContainerLayer();
   1.610 +  if (!LayerHasNonContainerDescendants(content)) {
   1.611 +    return;
   1.612 +  }
   1.613 +
   1.614 +  const FrameMetrics& metrics = content->GetFrameMetrics();
   1.615 +  AsyncPanZoomController* apzc = content->GetAsyncPanZoomController();
   1.616 +
   1.617 +  if (aScrollbarIsChild) {
   1.618 +    // Because we try to apply the scrollbar transform before we apply the async transform on
   1.619 +    // the actual content, we need to ensure that the APZC has updated any pending animations
   1.620 +    // to the current frame timestamp before we extract the transforms from it. The code in this
   1.621 +    // block accomplishes that and throws away the temp variables.
   1.622 +    // TODO: it might be cleaner to do a pass through the layer tree to advance all the APZC
   1.623 +    // transforms before updating the layer shadow transforms. That will allow removal of this code.
   1.624 +    ViewTransform treeTransform;
   1.625 +    ScreenPoint scrollOffset;
   1.626 +    apzc->SampleContentTransformForFrame(aCurrentFrame, &treeTransform, scrollOffset);
   1.627 +  }
   1.628 +
   1.629 +  gfx3DMatrix asyncTransform = gfx3DMatrix(apzc->GetCurrentAsyncTransform());
   1.630 +  gfx3DMatrix nontransientTransform = apzc->GetNontransientAsyncTransform();
   1.631 +  gfx3DMatrix transientTransform = asyncTransform * nontransientTransform.Inverse();
   1.632 +
   1.633 +  // |transientTransform| represents the amount by which we have scrolled and
   1.634 +  // zoomed since the last paint. Because the scrollbar was sized and positioned based
   1.635 +  // on the painted content, we need to adjust it based on transientTransform so that
   1.636 +  // it reflects what the user is actually seeing now.
   1.637 +  // - The scroll thumb needs to be scaled in the direction of scrolling by the inverse
   1.638 +  //   of the transientTransform scale (representing the zoom). This is because zooming
   1.639 +  //   in decreases the fraction of the whole scrollable rect that is in view.
   1.640 +  // - It needs to be translated in opposite direction of the transientTransform
   1.641 +  //   translation (representing the scroll). This is because scrolling down, which
   1.642 +  //   translates the layer content up, should result in moving the scroll thumb down.
   1.643 +  //   The amount of the translation to the scroll thumb should be such that the ratio
   1.644 +  //   of the translation to the size of the scroll port is the same as the ratio
   1.645 +  //   of the scroll amount to the size of the scrollable rect.
   1.646 +  Matrix4x4 scrollbarTransform;
   1.647 +  if (aScrollbar->GetScrollbarDirection() == Layer::VERTICAL) {
   1.648 +    float scale = metrics.CalculateCompositedSizeInCssPixels().height / metrics.mScrollableRect.height;
   1.649 +    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform.GetYScale(), 1.f);
   1.650 +    scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(0, -transientTransform._42 * scale, 0);
   1.651 +  }
   1.652 +  if (aScrollbar->GetScrollbarDirection() == Layer::HORIZONTAL) {
   1.653 +    float scale = metrics.CalculateCompositedSizeInCssPixels().width / metrics.mScrollableRect.width;
   1.654 +    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform.GetXScale(), 1.f, 1.f);
   1.655 +    scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(-transientTransform._41 * scale, 0, 0);
   1.656 +  }
   1.657 +
   1.658 +  Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
   1.659 +
   1.660 +  if (aScrollbarIsChild) {
   1.661 +    // If the scrollbar layer is a child of the content it is a scrollbar for, then we
   1.662 +    // need to do an extra untransform to cancel out the transient async transform on
   1.663 +    // the content. This is needed because otherwise that transient async transform is
   1.664 +    // part of the effective transform of this scrollbar, and the scrollbar will jitter
   1.665 +    // as the content scrolls.
   1.666 +    Matrix4x4 targetUntransform;
   1.667 +    ToMatrix4x4(transientTransform.Inverse(), targetUntransform);
   1.668 +    transform = transform * targetUntransform;
   1.669 +  }
   1.670 +
   1.671 +  // GetTransform already takes the pre- and post-scale into account.  Since we
   1.672 +  // will apply the pre- and post-scale again when computing the effective
   1.673 +  // transform, we must apply the inverses here.
   1.674 +  transform.Scale(1.0f/aScrollbar->GetPreXScale(),
   1.675 +                  1.0f/aScrollbar->GetPreYScale(),
   1.676 +                  1);
   1.677 +  transform = transform * Matrix4x4().Scale(1.0f/aScrollbar->GetPostXScale(),
   1.678 +                                            1.0f/aScrollbar->GetPostYScale(),
   1.679 +                                            1);
   1.680 +  aScrollbar->AsLayerComposite()->SetShadowTransform(transform);
   1.681 +}
   1.682 +
   1.683 +void
   1.684 +AsyncCompositionManager::ApplyAsyncTransformToScrollbar(TimeStamp aCurrentFrame, ContainerLayer* aLayer)
   1.685 +{
   1.686 +  // If this layer corresponds to a scrollbar, then there should be a layer that
   1.687 +  // is a previous sibling or a parent that has a matching ViewID on its FrameMetrics.
   1.688 +  // That is the content that this scrollbar is for. We pick up the transient
   1.689 +  // async transform from that layer and use it to update the scrollbar position.
   1.690 +  // Note that it is possible that the content layer is no longer there; in
   1.691 +  // this case we don't need to do anything because there can't be an async
   1.692 +  // transform on the content.
   1.693 +  // We only apply the transform if the scroll-target layer has non-container
   1.694 +  // children (i.e. when it has some possibly-visible content). This is to
   1.695 +  // avoid moving scroll-bars in the situation that only a scroll information
   1.696 +  // layer has been built for a scroll frame, as this would result in a
   1.697 +  // disparity between scrollbars and visible content.
   1.698 +  for (Layer* scrollTarget = aLayer->GetPrevSibling();
   1.699 +       scrollTarget;
   1.700 +       scrollTarget = scrollTarget->GetPrevSibling()) {
   1.701 +    if (LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
   1.702 +      // Found a sibling that matches our criteria
   1.703 +      ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, false);
   1.704 +      return;
   1.705 +    }
   1.706 +  }
   1.707 +
   1.708 +  // If we didn't find a sibling, look for a parent
   1.709 +  Layer* scrollTarget = aLayer->GetParent();
   1.710 +  if (scrollTarget && LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
   1.711 +    ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, true);
   1.712 +  }
   1.713 +}
   1.714 +
   1.715 +void
   1.716 +AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
   1.717 +{
   1.718 +  LayerComposite* layerComposite = aLayer->AsLayerComposite();
   1.719 +  ContainerLayer* container = aLayer->AsContainerLayer();
   1.720 +
   1.721 +  const FrameMetrics& metrics = container->GetFrameMetrics();
   1.722 +  // We must apply the resolution scale before a pan/zoom transform, so we call
   1.723 +  // GetTransform here.
   1.724 +  gfx3DMatrix currentTransform;
   1.725 +  To3DMatrix(aLayer->GetTransform(), currentTransform);
   1.726 +  Matrix4x4 oldTransform = aLayer->GetTransform();
   1.727 +
   1.728 +  gfx3DMatrix treeTransform;
   1.729 +
   1.730 +  CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel();
   1.731 +
   1.732 +  LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom);
   1.733 +
   1.734 +  if (mIsFirstPaint) {
   1.735 +    mContentRect = metrics.mScrollableRect;
   1.736 +    SetFirstPaintViewport(scrollOffsetLayerPixels,
   1.737 +                          geckoZoom,
   1.738 +                          mContentRect);
   1.739 +    mIsFirstPaint = false;
   1.740 +  } else if (!metrics.mScrollableRect.IsEqualEdges(mContentRect)) {
   1.741 +    mContentRect = metrics.mScrollableRect;
   1.742 +    SetPageRect(mContentRect);
   1.743 +  }
   1.744 +
   1.745 +  // We synchronise the viewport information with Java after sending the above
   1.746 +  // notifications, so that Java can take these into account in its response.
   1.747 +  // Calculate the absolute display port to send to Java
   1.748 +  LayerIntRect displayPort = RoundedToInt(
   1.749 +    (metrics.mCriticalDisplayPort.IsEmpty()
   1.750 +      ? metrics.mDisplayPort
   1.751 +      : metrics.mCriticalDisplayPort
   1.752 +    ) * geckoZoom);
   1.753 +  displayPort += scrollOffsetLayerPixels;
   1.754 +
   1.755 +  LayerMargin fixedLayerMargins(0, 0, 0, 0);
   1.756 +  ScreenPoint offset(0, 0);
   1.757 +
   1.758 +  // Ideally we would initialize userZoom to AsyncPanZoomController::CalculateResolution(metrics)
   1.759 +  // but this causes a reftest-ipc test to fail (see bug 883646 comment 27). The reason for this
   1.760 +  // appears to be that metrics.mZoom is poorly initialized in some scenarios. In these scenarios,
   1.761 +  // however, we can assume there is no async zooming in progress and so the following statement
   1.762 +  // works fine.
   1.763 +  CSSToScreenScale userZoom(metrics.mDevPixelsPerCSSPixel * metrics.mCumulativeResolution * LayerToScreenScale(1));
   1.764 +  ScreenPoint userScroll = metrics.GetScrollOffset() * userZoom;
   1.765 +  SyncViewportInfo(displayPort, geckoZoom, mLayersUpdated,
   1.766 +                   userScroll, userZoom, fixedLayerMargins,
   1.767 +                   offset);
   1.768 +  mLayersUpdated = false;
   1.769 +
   1.770 +  // Apply the render offset
   1.771 +  mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
   1.772 +
   1.773 +  // Handle transformations for asynchronous panning and zooming. We determine the
   1.774 +  // zoom used by Gecko from the transformation set on the root layer, and we
   1.775 +  // determine the scroll offset used by Gecko from the frame metrics of the
   1.776 +  // primary scrollable layer. We compare this to the user zoom and scroll
   1.777 +  // offset in the view transform we obtained from Java in order to compute the
   1.778 +  // transformation we need to apply.
   1.779 +  LayerToScreenScale zoomAdjust = userZoom / geckoZoom;
   1.780 +
   1.781 +  LayerPoint geckoScroll(0, 0);
   1.782 +  if (metrics.IsScrollable()) {
   1.783 +    geckoScroll = metrics.GetScrollOffset() * geckoZoom;
   1.784 +  }
   1.785 +
   1.786 +  LayerPoint translation = (userScroll / zoomAdjust) - geckoScroll;
   1.787 +  treeTransform = gfx3DMatrix(ViewTransform(-translation,
   1.788 +                                            userZoom
   1.789 +                                          / metrics.mDevPixelsPerCSSPixel
   1.790 +                                          / metrics.GetParentResolution()));
   1.791 +
   1.792 +  // The transform already takes the resolution scale into account.  Since we
   1.793 +  // will apply the resolution scale again when computing the effective
   1.794 +  // transform, we must apply the inverse resolution scale here.
   1.795 +  gfx3DMatrix computedTransform = treeTransform * currentTransform;
   1.796 +  computedTransform.Scale(1.0f/container->GetPreXScale(),
   1.797 +                          1.0f/container->GetPreYScale(),
   1.798 +                          1);
   1.799 +  computedTransform.ScalePost(1.0f/container->GetPostXScale(),
   1.800 +                              1.0f/container->GetPostYScale(),
   1.801 +                              1);
   1.802 +  Matrix4x4 matrix;
   1.803 +  ToMatrix4x4(computedTransform, matrix);
   1.804 +  layerComposite->SetShadowTransform(matrix);
   1.805 +  NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
   1.806 +               "overwriting animated transform!");
   1.807 +
   1.808 +  // Apply resolution scaling to the old transform - the layer tree as it is
   1.809 +  // doesn't have the necessary transform to display correctly.
   1.810 +  oldTransform.Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1);
   1.811 +
   1.812 +  // Make sure that overscroll and under-zoom are represented in the old
   1.813 +  // transform so that fixed position content moves and scales accordingly.
   1.814 +  // These calculations will effectively scale and offset fixed position layers
   1.815 +  // in screen space when the compensatory transform is performed in
   1.816 +  // AlignFixedAndStickyLayers.
   1.817 +  ScreenRect contentScreenRect = mContentRect * userZoom;
   1.818 +  gfxPoint3D overscrollTranslation;
   1.819 +  if (userScroll.x < contentScreenRect.x) {
   1.820 +    overscrollTranslation.x = contentScreenRect.x - userScroll.x;
   1.821 +  } else if (userScroll.x + metrics.mCompositionBounds.width > contentScreenRect.XMost()) {
   1.822 +    overscrollTranslation.x = contentScreenRect.XMost() -
   1.823 +      (userScroll.x + metrics.mCompositionBounds.width);
   1.824 +  }
   1.825 +  if (userScroll.y < contentScreenRect.y) {
   1.826 +    overscrollTranslation.y = contentScreenRect.y - userScroll.y;
   1.827 +  } else if (userScroll.y + metrics.mCompositionBounds.height > contentScreenRect.YMost()) {
   1.828 +    overscrollTranslation.y = contentScreenRect.YMost() -
   1.829 +      (userScroll.y + metrics.mCompositionBounds.height);
   1.830 +  }
   1.831 +  oldTransform.Translate(overscrollTranslation.x,
   1.832 +                         overscrollTranslation.y,
   1.833 +                         overscrollTranslation.z);
   1.834 +
   1.835 +  gfx::Size underZoomScale(1.0f, 1.0f);
   1.836 +  if (mContentRect.width * userZoom.scale < metrics.mCompositionBounds.width) {
   1.837 +    underZoomScale.width = (mContentRect.width * userZoom.scale) /
   1.838 +      metrics.mCompositionBounds.width;
   1.839 +  }
   1.840 +  if (mContentRect.height * userZoom.scale < metrics.mCompositionBounds.height) {
   1.841 +    underZoomScale.height = (mContentRect.height * userZoom.scale) /
   1.842 +      metrics.mCompositionBounds.height;
   1.843 +  }
   1.844 +  oldTransform.Scale(underZoomScale.width, underZoomScale.height, 1);
   1.845 +
   1.846 +  // Make sure fixed position layers don't move away from their anchor points
   1.847 +  // when we're asynchronously panning or zooming
   1.848 +  AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform, fixedLayerMargins);
   1.849 +}
   1.850 +
   1.851 +bool
   1.852 +AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame)
   1.853 +{
   1.854 +  PROFILER_LABEL("AsyncCompositionManager", "TransformShadowTree");
   1.855 +  Layer* root = mLayerManager->GetRoot();
   1.856 +  if (!root) {
   1.857 +    return false;
   1.858 +  }
   1.859 +
   1.860 +  // NB: we must sample animations *before* sampling pan/zoom
   1.861 +  // transforms.
   1.862 +  bool wantNextFrame = SampleAnimations(root, aCurrentFrame);
   1.863 +
   1.864 +  // FIXME/bug 775437: unify this interface with the ~native-fennec
   1.865 +  // derived code
   1.866 +  //
   1.867 +  // Attempt to apply an async content transform to any layer that has
   1.868 +  // an async pan zoom controller (which means that it is rendered
   1.869 +  // async using Gecko). If this fails, fall back to transforming the
   1.870 +  // primary scrollable layer.  "Failing" here means that we don't
   1.871 +  // find a frame that is async scrollable.  Note that the fallback
   1.872 +  // code also includes Fennec which is rendered async.  Fennec uses
   1.873 +  // its own platform-specific async rendering that is done partially
   1.874 +  // in Gecko and partially in Java.
   1.875 +  if (!ApplyAsyncContentTransformToTree(aCurrentFrame, root, &wantNextFrame)) {
   1.876 +    nsAutoTArray<Layer*,1> scrollableLayers;
   1.877 +#ifdef MOZ_WIDGET_ANDROID
   1.878 +    scrollableLayers.AppendElement(mLayerManager->GetPrimaryScrollableLayer());
   1.879 +#else
   1.880 +    mLayerManager->GetScrollableLayers(scrollableLayers);
   1.881 +#endif
   1.882 +
   1.883 +    for (uint32_t i = 0; i < scrollableLayers.Length(); i++) {
   1.884 +      if (scrollableLayers[i]) {
   1.885 +        TransformScrollableLayer(scrollableLayers[i]);
   1.886 +      }
   1.887 +    }
   1.888 +  }
   1.889 +
   1.890 +  return wantNextFrame;
   1.891 +}
   1.892 +
   1.893 +void
   1.894 +AsyncCompositionManager::SetFirstPaintViewport(const LayerIntPoint& aOffset,
   1.895 +                                               const CSSToLayerScale& aZoom,
   1.896 +                                               const CSSRect& aCssPageRect)
   1.897 +{
   1.898 +#ifdef MOZ_WIDGET_ANDROID
   1.899 +  AndroidBridge::Bridge()->SetFirstPaintViewport(aOffset, aZoom, aCssPageRect);
   1.900 +#endif
   1.901 +}
   1.902 +
   1.903 +void
   1.904 +AsyncCompositionManager::SetPageRect(const CSSRect& aCssPageRect)
   1.905 +{
   1.906 +#ifdef MOZ_WIDGET_ANDROID
   1.907 +  AndroidBridge::Bridge()->SetPageRect(aCssPageRect);
   1.908 +#endif
   1.909 +}
   1.910 +
   1.911 +void
   1.912 +AsyncCompositionManager::SyncViewportInfo(const LayerIntRect& aDisplayPort,
   1.913 +                                          const CSSToLayerScale& aDisplayResolution,
   1.914 +                                          bool aLayersUpdated,
   1.915 +                                          ScreenPoint& aScrollOffset,
   1.916 +                                          CSSToScreenScale& aScale,
   1.917 +                                          LayerMargin& aFixedLayerMargins,
   1.918 +                                          ScreenPoint& aOffset)
   1.919 +{
   1.920 +#ifdef MOZ_WIDGET_ANDROID
   1.921 +  AndroidBridge::Bridge()->SyncViewportInfo(aDisplayPort,
   1.922 +                                            aDisplayResolution,
   1.923 +                                            aLayersUpdated,
   1.924 +                                            aScrollOffset,
   1.925 +                                            aScale,
   1.926 +                                            aFixedLayerMargins,
   1.927 +                                            aOffset);
   1.928 +#endif
   1.929 +}
   1.930 +
   1.931 +void
   1.932 +AsyncCompositionManager::SyncFrameMetrics(const ScreenPoint& aScrollOffset,
   1.933 +                                          float aZoom,
   1.934 +                                          const CSSRect& aCssPageRect,
   1.935 +                                          bool aLayersUpdated,
   1.936 +                                          const CSSRect& aDisplayPort,
   1.937 +                                          const CSSToLayerScale& aDisplayResolution,
   1.938 +                                          bool aIsFirstPaint,
   1.939 +                                          LayerMargin& aFixedLayerMargins,
   1.940 +                                          ScreenPoint& aOffset)
   1.941 +{
   1.942 +#ifdef MOZ_WIDGET_ANDROID
   1.943 +  AndroidBridge::Bridge()->SyncFrameMetrics(aScrollOffset, aZoom, aCssPageRect,
   1.944 +                                            aLayersUpdated, aDisplayPort,
   1.945 +                                            aDisplayResolution, aIsFirstPaint,
   1.946 +                                            aFixedLayerMargins, aOffset);
   1.947 +#endif
   1.948 +}
   1.949 +
   1.950 +} // namespace layers
   1.951 +} // namespace mozilla

mercurial