gfx/layers/composite/AsyncCompositionManager.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set sw=2 ts=2 et tw=80 : */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "mozilla/layers/AsyncCompositionManager.h"
michael@0 8 #include <stdint.h> // for uint32_t
michael@0 9 #include "AnimationCommon.h" // for ComputedTimingFunction
michael@0 10 #include "CompositorParent.h" // for CompositorParent, etc
michael@0 11 #include "FrameMetrics.h" // for FrameMetrics
michael@0 12 #include "LayerManagerComposite.h" // for LayerManagerComposite, etc
michael@0 13 #include "Layers.h" // for Layer, ContainerLayer, etc
michael@0 14 #include "gfxPoint.h" // for gfxPoint, gfxSize
michael@0 15 #include "gfxPoint3D.h" // for gfxPoint3D
michael@0 16 #include "mozilla/WidgetUtils.h" // for ComputeTransformForRotation
michael@0 17 #include "mozilla/gfx/BaseRect.h" // for BaseRect
michael@0 18 #include "mozilla/gfx/Point.h" // for RoundedToInt, PointTyped
michael@0 19 #include "mozilla/gfx/Rect.h" // for RoundedToInt, RectTyped
michael@0 20 #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
michael@0 21 #include "mozilla/layers/AsyncPanZoomController.h"
michael@0 22 #include "mozilla/layers/Compositor.h" // for Compositor
michael@0 23 #include "nsAnimationManager.h" // for ElementAnimations
michael@0 24 #include "nsCSSPropList.h"
michael@0 25 #include "nsCoord.h" // for NSAppUnitsToFloatPixels, etc
michael@0 26 #include "nsDebug.h" // for NS_ASSERTION, etc
michael@0 27 #include "nsDeviceContext.h" // for nsDeviceContext
michael@0 28 #include "nsDisplayList.h" // for nsDisplayTransform, etc
michael@0 29 #include "nsMathUtils.h" // for NS_round
michael@0 30 #include "nsPoint.h" // for nsPoint
michael@0 31 #include "nsRect.h" // for nsIntRect
michael@0 32 #include "nsRegion.h" // for nsIntRegion
michael@0 33 #include "nsStyleAnimation.h" // for nsStyleAnimation::Value, etc
michael@0 34 #include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
michael@0 35 #include "nsTArrayForwardDeclare.h" // for InfallibleTArray
michael@0 36 #if defined(MOZ_WIDGET_ANDROID)
michael@0 37 # include <android/log.h>
michael@0 38 # include "AndroidBridge.h"
michael@0 39 #endif
michael@0 40 #include "GeckoProfiler.h"
michael@0 41
michael@0 42 struct nsCSSValueSharedList;
michael@0 43
michael@0 44 using namespace mozilla::dom;
michael@0 45 using namespace mozilla::gfx;
michael@0 46
michael@0 47 namespace mozilla {
michael@0 48 namespace layers {
michael@0 49
michael@0 50 enum Op { Resolve, Detach };
michael@0 51
michael@0 52 static bool
michael@0 53 IsSameDimension(ScreenOrientation o1, ScreenOrientation o2)
michael@0 54 {
michael@0 55 bool isO1portrait = (o1 == eScreenOrientation_PortraitPrimary || o1 == eScreenOrientation_PortraitSecondary);
michael@0 56 bool isO2portrait = (o2 == eScreenOrientation_PortraitPrimary || o2 == eScreenOrientation_PortraitSecondary);
michael@0 57 return !(isO1portrait ^ isO2portrait);
michael@0 58 }
michael@0 59
michael@0 60 static bool
michael@0 61 ContentMightReflowOnOrientationChange(const nsIntRect& rect)
michael@0 62 {
michael@0 63 return rect.width != rect.height;
michael@0 64 }
michael@0 65
michael@0 66 template<Op OP>
michael@0 67 static void
michael@0 68 WalkTheTree(Layer* aLayer,
michael@0 69 bool& aReady,
michael@0 70 const TargetConfig& aTargetConfig)
michael@0 71 {
michael@0 72 if (RefLayer* ref = aLayer->AsRefLayer()) {
michael@0 73 if (const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(ref->GetReferentId())) {
michael@0 74 if (Layer* referent = state->mRoot) {
michael@0 75 if (!ref->GetVisibleRegion().IsEmpty()) {
michael@0 76 ScreenOrientation chromeOrientation = aTargetConfig.orientation();
michael@0 77 ScreenOrientation contentOrientation = state->mTargetConfig.orientation();
michael@0 78 if (!IsSameDimension(chromeOrientation, contentOrientation) &&
michael@0 79 ContentMightReflowOnOrientationChange(aTargetConfig.clientBounds())) {
michael@0 80 aReady = false;
michael@0 81 }
michael@0 82 }
michael@0 83
michael@0 84 if (OP == Resolve) {
michael@0 85 ref->ConnectReferentLayer(referent);
michael@0 86 } else {
michael@0 87 ref->DetachReferentLayer(referent);
michael@0 88 }
michael@0 89 }
michael@0 90 }
michael@0 91 }
michael@0 92 for (Layer* child = aLayer->GetFirstChild();
michael@0 93 child; child = child->GetNextSibling()) {
michael@0 94 WalkTheTree<OP>(child, aReady, aTargetConfig);
michael@0 95 }
michael@0 96 }
michael@0 97
michael@0 98 void
michael@0 99 AsyncCompositionManager::ResolveRefLayers()
michael@0 100 {
michael@0 101 if (!mLayerManager->GetRoot()) {
michael@0 102 return;
michael@0 103 }
michael@0 104
michael@0 105 mReadyForCompose = true;
michael@0 106 WalkTheTree<Resolve>(mLayerManager->GetRoot(),
michael@0 107 mReadyForCompose,
michael@0 108 mTargetConfig);
michael@0 109 }
michael@0 110
michael@0 111 void
michael@0 112 AsyncCompositionManager::DetachRefLayers()
michael@0 113 {
michael@0 114 if (!mLayerManager->GetRoot()) {
michael@0 115 return;
michael@0 116 }
michael@0 117 WalkTheTree<Detach>(mLayerManager->GetRoot(),
michael@0 118 mReadyForCompose,
michael@0 119 mTargetConfig);
michael@0 120 }
michael@0 121
michael@0 122 void
michael@0 123 AsyncCompositionManager::ComputeRotation()
michael@0 124 {
michael@0 125 if (!mTargetConfig.naturalBounds().IsEmpty()) {
michael@0 126 mLayerManager->SetWorldTransform(
michael@0 127 ComputeTransformForRotation(mTargetConfig.naturalBounds(),
michael@0 128 mTargetConfig.rotation()));
michael@0 129 }
michael@0 130 }
michael@0 131
michael@0 132 static bool
michael@0 133 GetBaseTransform2D(Layer* aLayer, Matrix* aTransform)
michael@0 134 {
michael@0 135 // Start with the animated transform if there is one
michael@0 136 return (aLayer->AsLayerComposite()->GetShadowTransformSetByAnimation() ?
michael@0 137 aLayer->GetLocalTransform() : aLayer->GetTransform()).Is2D(aTransform);
michael@0 138 }
michael@0 139
michael@0 140 static void
michael@0 141 TranslateShadowLayer2D(Layer* aLayer,
michael@0 142 const gfxPoint& aTranslation)
michael@0 143 {
michael@0 144 Matrix layerTransform;
michael@0 145 if (!GetBaseTransform2D(aLayer, &layerTransform)) {
michael@0 146 return;
michael@0 147 }
michael@0 148
michael@0 149 // Apply the 2D translation to the layer transform.
michael@0 150 layerTransform._31 += aTranslation.x;
michael@0 151 layerTransform._32 += aTranslation.y;
michael@0 152
michael@0 153 // The transform already takes the resolution scale into account. Since we
michael@0 154 // will apply the resolution scale again when computing the effective
michael@0 155 // transform, we must apply the inverse resolution scale here.
michael@0 156 Matrix4x4 layerTransform3D = Matrix4x4::From2D(layerTransform);
michael@0 157 if (ContainerLayer* c = aLayer->AsContainerLayer()) {
michael@0 158 layerTransform3D.Scale(1.0f/c->GetPreXScale(),
michael@0 159 1.0f/c->GetPreYScale(),
michael@0 160 1);
michael@0 161 }
michael@0 162 layerTransform3D = layerTransform3D *
michael@0 163 Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
michael@0 164 1.0f/aLayer->GetPostYScale(),
michael@0 165 1);
michael@0 166
michael@0 167 LayerComposite* layerComposite = aLayer->AsLayerComposite();
michael@0 168 layerComposite->SetShadowTransform(layerTransform3D);
michael@0 169 layerComposite->SetShadowTransformSetByAnimation(false);
michael@0 170
michael@0 171 const nsIntRect* clipRect = aLayer->GetClipRect();
michael@0 172 if (clipRect) {
michael@0 173 nsIntRect transformedClipRect(*clipRect);
michael@0 174 transformedClipRect.MoveBy(aTranslation.x, aTranslation.y);
michael@0 175 layerComposite->SetShadowClipRect(&transformedClipRect);
michael@0 176 }
michael@0 177 }
michael@0 178
michael@0 179 static bool
michael@0 180 AccumulateLayerTransforms2D(Layer* aLayer,
michael@0 181 Layer* aAncestor,
michael@0 182 Matrix& aMatrix)
michael@0 183 {
michael@0 184 // Accumulate the transforms between this layer and the subtree root layer.
michael@0 185 for (Layer* l = aLayer; l && l != aAncestor; l = l->GetParent()) {
michael@0 186 Matrix l2D;
michael@0 187 if (!GetBaseTransform2D(l, &l2D)) {
michael@0 188 return false;
michael@0 189 }
michael@0 190 aMatrix *= l2D;
michael@0 191 }
michael@0 192
michael@0 193 return true;
michael@0 194 }
michael@0 195
michael@0 196 static LayerPoint
michael@0 197 GetLayerFixedMarginsOffset(Layer* aLayer,
michael@0 198 const LayerMargin& aFixedLayerMargins)
michael@0 199 {
michael@0 200 // Work out the necessary translation, in root scrollable layer space.
michael@0 201 // Because fixed layer margins are stored relative to the root scrollable
michael@0 202 // layer, we can just take the difference between these values.
michael@0 203 LayerPoint translation;
michael@0 204 const LayerPoint& anchor = aLayer->GetFixedPositionAnchor();
michael@0 205 const LayerMargin& fixedMargins = aLayer->GetFixedPositionMargins();
michael@0 206
michael@0 207 if (fixedMargins.left >= 0) {
michael@0 208 if (anchor.x > 0) {
michael@0 209 translation.x -= aFixedLayerMargins.right - fixedMargins.right;
michael@0 210 } else {
michael@0 211 translation.x += aFixedLayerMargins.left - fixedMargins.left;
michael@0 212 }
michael@0 213 }
michael@0 214
michael@0 215 if (fixedMargins.top >= 0) {
michael@0 216 if (anchor.y > 0) {
michael@0 217 translation.y -= aFixedLayerMargins.bottom - fixedMargins.bottom;
michael@0 218 } else {
michael@0 219 translation.y += aFixedLayerMargins.top - fixedMargins.top;
michael@0 220 }
michael@0 221 }
michael@0 222
michael@0 223 return translation;
michael@0 224 }
michael@0 225
michael@0 226 static gfxFloat
michael@0 227 IntervalOverlap(gfxFloat aTranslation, gfxFloat aMin, gfxFloat aMax)
michael@0 228 {
michael@0 229 // Determine the amount of overlap between the 1D vector |aTranslation|
michael@0 230 // and the interval [aMin, aMax].
michael@0 231 if (aTranslation > 0) {
michael@0 232 return std::max(0.0, std::min(aMax, aTranslation) - std::max(aMin, 0.0));
michael@0 233 } else {
michael@0 234 return std::min(0.0, std::max(aMin, aTranslation) - std::min(aMax, 0.0));
michael@0 235 }
michael@0 236 }
michael@0 237
michael@0 238 void
michael@0 239 AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
michael@0 240 Layer* aTransformedSubtreeRoot,
michael@0 241 const Matrix4x4& aPreviousTransformForRoot,
michael@0 242 const LayerMargin& aFixedLayerMargins)
michael@0 243 {
michael@0 244 bool isRootFixed = aLayer->GetIsFixedPosition() &&
michael@0 245 !aLayer->GetParent()->GetIsFixedPosition();
michael@0 246 bool isStickyForSubtree = aLayer->GetIsStickyPosition() &&
michael@0 247 aTransformedSubtreeRoot->AsContainerLayer() &&
michael@0 248 aLayer->GetStickyScrollContainerId() ==
michael@0 249 aTransformedSubtreeRoot->AsContainerLayer()->GetFrameMetrics().GetScrollId();
michael@0 250 if (aLayer != aTransformedSubtreeRoot && (isRootFixed || isStickyForSubtree)) {
michael@0 251 // Insert a translation so that the position of the anchor point is the same
michael@0 252 // before and after the change to the transform of aTransformedSubtreeRoot.
michael@0 253 // This currently only works for fixed layers with 2D transforms.
michael@0 254
michael@0 255 // Accumulate the transforms between this layer and the subtree root layer.
michael@0 256 Matrix ancestorTransform;
michael@0 257 if (!AccumulateLayerTransforms2D(aLayer->GetParent(), aTransformedSubtreeRoot,
michael@0 258 ancestorTransform)) {
michael@0 259 return;
michael@0 260 }
michael@0 261
michael@0 262 Matrix oldRootTransform;
michael@0 263 Matrix newRootTransform;
michael@0 264 if (!aPreviousTransformForRoot.Is2D(&oldRootTransform) ||
michael@0 265 !aTransformedSubtreeRoot->GetLocalTransform().Is2D(&newRootTransform)) {
michael@0 266 return;
michael@0 267 }
michael@0 268
michael@0 269 // Calculate the cumulative transforms between the subtree root with the
michael@0 270 // old transform and the current transform.
michael@0 271 Matrix oldCumulativeTransform = ancestorTransform * oldRootTransform;
michael@0 272 Matrix newCumulativeTransform = ancestorTransform * newRootTransform;
michael@0 273 if (newCumulativeTransform.IsSingular()) {
michael@0 274 return;
michael@0 275 }
michael@0 276 Matrix newCumulativeTransformInverse = newCumulativeTransform;
michael@0 277 newCumulativeTransformInverse.Invert();
michael@0 278
michael@0 279 // Now work out the translation necessary to make sure the layer doesn't
michael@0 280 // move given the new sub-tree root transform.
michael@0 281 Matrix layerTransform;
michael@0 282 if (!GetBaseTransform2D(aLayer, &layerTransform)) {
michael@0 283 return;
michael@0 284 }
michael@0 285
michael@0 286 // Calculate any offset necessary, in previous transform sub-tree root
michael@0 287 // space. This is used to make sure fixed position content respects
michael@0 288 // content document fixed position margins.
michael@0 289 LayerPoint offsetInOldSubtreeLayerSpace = GetLayerFixedMarginsOffset(aLayer, aFixedLayerMargins);
michael@0 290
michael@0 291 // Add the above offset to the anchor point so we can offset the layer by
michael@0 292 // and amount that's specified in old subtree layer space.
michael@0 293 const LayerPoint& anchorInOldSubtreeLayerSpace = aLayer->GetFixedPositionAnchor();
michael@0 294 LayerPoint offsetAnchorInOldSubtreeLayerSpace = anchorInOldSubtreeLayerSpace + offsetInOldSubtreeLayerSpace;
michael@0 295
michael@0 296 // Add the local layer transform to the two points to make the equation
michael@0 297 // below this section more convenient.
michael@0 298 Point anchor(anchorInOldSubtreeLayerSpace.x, anchorInOldSubtreeLayerSpace.y);
michael@0 299 Point offsetAnchor(offsetAnchorInOldSubtreeLayerSpace.x, offsetAnchorInOldSubtreeLayerSpace.y);
michael@0 300 Point locallyTransformedAnchor = layerTransform * anchor;
michael@0 301 Point locallyTransformedOffsetAnchor = layerTransform * offsetAnchor;
michael@0 302
michael@0 303 // Transforming the locallyTransformedAnchor by oldCumulativeTransform
michael@0 304 // returns the layer's anchor point relative to the parent of
michael@0 305 // aTransformedSubtreeRoot, before the new transform was applied.
michael@0 306 // Then, applying newCumulativeTransformInverse maps that point relative
michael@0 307 // to the layer's parent, which is the same coordinate space as
michael@0 308 // locallyTransformedAnchor again, allowing us to subtract them and find
michael@0 309 // out the offset necessary to make sure the layer stays stationary.
michael@0 310 Point oldAnchorPositionInNewSpace =
michael@0 311 newCumulativeTransformInverse * (oldCumulativeTransform * locallyTransformedOffsetAnchor);
michael@0 312 Point translation = oldAnchorPositionInNewSpace - locallyTransformedAnchor;
michael@0 313
michael@0 314 if (aLayer->GetIsStickyPosition()) {
michael@0 315 // For sticky positioned layers, the difference between the two rectangles
michael@0 316 // defines a pair of translation intervals in each dimension through which
michael@0 317 // the layer should not move relative to the scroll container. To
michael@0 318 // accomplish this, we limit each dimension of the |translation| to that
michael@0 319 // part of it which overlaps those intervals.
michael@0 320 const LayerRect& stickyOuter = aLayer->GetStickyScrollRangeOuter();
michael@0 321 const LayerRect& stickyInner = aLayer->GetStickyScrollRangeInner();
michael@0 322
michael@0 323 translation.y = IntervalOverlap(translation.y, stickyOuter.y, stickyOuter.YMost()) -
michael@0 324 IntervalOverlap(translation.y, stickyInner.y, stickyInner.YMost());
michael@0 325 translation.x = IntervalOverlap(translation.x, stickyOuter.x, stickyOuter.XMost()) -
michael@0 326 IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost());
michael@0 327 }
michael@0 328
michael@0 329 // Finally, apply the 2D translation to the layer transform.
michael@0 330 TranslateShadowLayer2D(aLayer, ThebesPoint(translation));
michael@0 331
michael@0 332 // The transform has now been applied, so there's no need to iterate over
michael@0 333 // child layers.
michael@0 334 return;
michael@0 335 }
michael@0 336
michael@0 337 // Fixed layers are relative to their nearest scrollable layer, so when we
michael@0 338 // encounter a scrollable layer, reset the transform to that layer and remove
michael@0 339 // the fixed margins.
michael@0 340 if (aLayer->AsContainerLayer() &&
michael@0 341 aLayer->AsContainerLayer()->GetFrameMetrics().IsScrollable() &&
michael@0 342 aLayer != aTransformedSubtreeRoot) {
michael@0 343 AlignFixedAndStickyLayers(aLayer, aLayer, aLayer->GetTransform(), LayerMargin(0, 0, 0, 0));
michael@0 344 return;
michael@0 345 }
michael@0 346
michael@0 347 for (Layer* child = aLayer->GetFirstChild();
michael@0 348 child; child = child->GetNextSibling()) {
michael@0 349 AlignFixedAndStickyLayers(child, aTransformedSubtreeRoot,
michael@0 350 aPreviousTransformForRoot, aFixedLayerMargins);
michael@0 351 }
michael@0 352 }
michael@0 353
michael@0 354 static void
michael@0 355 SampleValue(float aPortion, Animation& aAnimation, nsStyleAnimation::Value& aStart,
michael@0 356 nsStyleAnimation::Value& aEnd, Animatable* aValue)
michael@0 357 {
michael@0 358 nsStyleAnimation::Value interpolatedValue;
michael@0 359 NS_ASSERTION(aStart.GetUnit() == aEnd.GetUnit() ||
michael@0 360 aStart.GetUnit() == nsStyleAnimation::eUnit_None ||
michael@0 361 aEnd.GetUnit() == nsStyleAnimation::eUnit_None, "Must have same unit");
michael@0 362 nsStyleAnimation::Interpolate(aAnimation.property(), aStart, aEnd,
michael@0 363 aPortion, interpolatedValue);
michael@0 364 if (aAnimation.property() == eCSSProperty_opacity) {
michael@0 365 *aValue = interpolatedValue.GetFloatValue();
michael@0 366 return;
michael@0 367 }
michael@0 368
michael@0 369 nsCSSValueSharedList* interpolatedList =
michael@0 370 interpolatedValue.GetCSSValueSharedListValue();
michael@0 371
michael@0 372 TransformData& data = aAnimation.data().get_TransformData();
michael@0 373 nsPoint origin = data.origin();
michael@0 374 // we expect all our transform data to arrive in css pixels, so here we must
michael@0 375 // adjust to dev pixels.
michael@0 376 double cssPerDev = double(nsDeviceContext::AppUnitsPerCSSPixel())
michael@0 377 / double(data.appUnitsPerDevPixel());
michael@0 378 gfxPoint3D transformOrigin = data.transformOrigin();
michael@0 379 transformOrigin.x = transformOrigin.x * cssPerDev;
michael@0 380 transformOrigin.y = transformOrigin.y * cssPerDev;
michael@0 381 gfxPoint3D perspectiveOrigin = data.perspectiveOrigin();
michael@0 382 perspectiveOrigin.x = perspectiveOrigin.x * cssPerDev;
michael@0 383 perspectiveOrigin.y = perspectiveOrigin.y * cssPerDev;
michael@0 384 nsDisplayTransform::FrameTransformProperties props(interpolatedList,
michael@0 385 transformOrigin,
michael@0 386 perspectiveOrigin,
michael@0 387 data.perspective());
michael@0 388 gfx3DMatrix transform =
michael@0 389 nsDisplayTransform::GetResultingTransformMatrix(props, origin,
michael@0 390 data.appUnitsPerDevPixel(),
michael@0 391 &data.bounds());
michael@0 392 gfxPoint3D scaledOrigin =
michael@0 393 gfxPoint3D(NS_round(NSAppUnitsToFloatPixels(origin.x, data.appUnitsPerDevPixel())),
michael@0 394 NS_round(NSAppUnitsToFloatPixels(origin.y, data.appUnitsPerDevPixel())),
michael@0 395 0.0f);
michael@0 396
michael@0 397 transform.Translate(scaledOrigin);
michael@0 398
michael@0 399 InfallibleTArray<TransformFunction> functions;
michael@0 400 Matrix4x4 realTransform;
michael@0 401 ToMatrix4x4(transform, realTransform);
michael@0 402 functions.AppendElement(TransformMatrix(realTransform));
michael@0 403 *aValue = functions;
michael@0 404 }
michael@0 405
michael@0 406 static bool
michael@0 407 SampleAnimations(Layer* aLayer, TimeStamp aPoint)
michael@0 408 {
michael@0 409 AnimationArray& animations = aLayer->GetAnimations();
michael@0 410 InfallibleTArray<AnimData>& animationData = aLayer->GetAnimationData();
michael@0 411
michael@0 412 bool activeAnimations = false;
michael@0 413
michael@0 414 for (uint32_t i = animations.Length(); i-- !=0; ) {
michael@0 415 Animation& animation = animations[i];
michael@0 416 AnimData& animData = animationData[i];
michael@0 417
michael@0 418 activeAnimations = true;
michael@0 419
michael@0 420 TimeDuration elapsedDuration = aPoint - animation.startTime();
michael@0 421 // Skip animations that are yet to start.
michael@0 422 //
michael@0 423 // Currently, this should only happen when the refresh driver is under test
michael@0 424 // control and is made to produce a time in the past or is restored from
michael@0 425 // test control causing it to jump backwards in time.
michael@0 426 //
michael@0 427 // Since activeAnimations is true, this could mean we keep compositing
michael@0 428 // unnecessarily during the delay, but so long as this only happens while
michael@0 429 // the refresh driver is under test control that should be ok.
michael@0 430 if (elapsedDuration.ToSeconds() < 0) {
michael@0 431 continue;
michael@0 432 }
michael@0 433
michael@0 434 double numIterations = animation.numIterations() != -1 ?
michael@0 435 animation.numIterations() : NS_IEEEPositiveInfinity();
michael@0 436 double positionInIteration =
michael@0 437 ElementAnimations::GetPositionInIteration(elapsedDuration,
michael@0 438 animation.duration(),
michael@0 439 numIterations,
michael@0 440 animation.direction());
michael@0 441
michael@0 442 NS_ABORT_IF_FALSE(0.0 <= positionInIteration &&
michael@0 443 positionInIteration <= 1.0,
michael@0 444 "position should be in [0-1]");
michael@0 445
michael@0 446 int segmentIndex = 0;
michael@0 447 AnimationSegment* segment = animation.segments().Elements();
michael@0 448 while (segment->endPortion() < positionInIteration) {
michael@0 449 ++segment;
michael@0 450 ++segmentIndex;
michael@0 451 }
michael@0 452
michael@0 453 double positionInSegment = (positionInIteration - segment->startPortion()) /
michael@0 454 (segment->endPortion() - segment->startPortion());
michael@0 455
michael@0 456 double portion = animData.mFunctions[segmentIndex]->GetValue(positionInSegment);
michael@0 457
michael@0 458 // interpolate the property
michael@0 459 Animatable interpolatedValue;
michael@0 460 SampleValue(portion, animation, animData.mStartValues[segmentIndex],
michael@0 461 animData.mEndValues[segmentIndex], &interpolatedValue);
michael@0 462 LayerComposite* layerComposite = aLayer->AsLayerComposite();
michael@0 463 switch (animation.property()) {
michael@0 464 case eCSSProperty_opacity:
michael@0 465 {
michael@0 466 layerComposite->SetShadowOpacity(interpolatedValue.get_float());
michael@0 467 break;
michael@0 468 }
michael@0 469 case eCSSProperty_transform:
michael@0 470 {
michael@0 471 Matrix4x4 matrix = interpolatedValue.get_ArrayOfTransformFunction()[0].get_TransformMatrix().value();
michael@0 472 if (ContainerLayer* c = aLayer->AsContainerLayer()) {
michael@0 473 matrix = matrix * Matrix4x4().Scale(c->GetInheritedXScale(),
michael@0 474 c->GetInheritedYScale(),
michael@0 475 1);
michael@0 476 }
michael@0 477 layerComposite->SetShadowTransform(matrix);
michael@0 478 layerComposite->SetShadowTransformSetByAnimation(true);
michael@0 479 break;
michael@0 480 }
michael@0 481 default:
michael@0 482 NS_WARNING("Unhandled animated property");
michael@0 483 }
michael@0 484 }
michael@0 485
michael@0 486 for (Layer* child = aLayer->GetFirstChild(); child;
michael@0 487 child = child->GetNextSibling()) {
michael@0 488 activeAnimations |= SampleAnimations(child, aPoint);
michael@0 489 }
michael@0 490
michael@0 491 return activeAnimations;
michael@0 492 }
michael@0 493
michael@0 494 bool
michael@0 495 AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame,
michael@0 496 Layer *aLayer,
michael@0 497 bool* aWantNextFrame)
michael@0 498 {
michael@0 499 bool appliedTransform = false;
michael@0 500 for (Layer* child = aLayer->GetFirstChild();
michael@0 501 child; child = child->GetNextSibling()) {
michael@0 502 appliedTransform |=
michael@0 503 ApplyAsyncContentTransformToTree(aCurrentFrame, child, aWantNextFrame);
michael@0 504 }
michael@0 505
michael@0 506 ContainerLayer* container = aLayer->AsContainerLayer();
michael@0 507 if (!container) {
michael@0 508 return appliedTransform;
michael@0 509 }
michael@0 510
michael@0 511 if (AsyncPanZoomController* controller = container->GetAsyncPanZoomController()) {
michael@0 512 LayerComposite* layerComposite = aLayer->AsLayerComposite();
michael@0 513 Matrix4x4 oldTransform = aLayer->GetTransform();
michael@0 514
michael@0 515 ViewTransform treeTransform;
michael@0 516 ScreenPoint scrollOffset;
michael@0 517 *aWantNextFrame |=
michael@0 518 controller->SampleContentTransformForFrame(aCurrentFrame,
michael@0 519 &treeTransform,
michael@0 520 scrollOffset);
michael@0 521
michael@0 522 const FrameMetrics& metrics = container->GetFrameMetrics();
michael@0 523 CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
michael@0 524 CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ?
michael@0 525 metrics.mDisplayPort : metrics.mCriticalDisplayPort);
michael@0 526 LayerMargin fixedLayerMargins(0, 0, 0, 0);
michael@0 527 ScreenPoint offset(0, 0);
michael@0 528 SyncFrameMetrics(scrollOffset, treeTransform.mScale.scale, metrics.mScrollableRect,
michael@0 529 mLayersUpdated, displayPort, paintScale,
michael@0 530 mIsFirstPaint, fixedLayerMargins, offset);
michael@0 531
michael@0 532 mIsFirstPaint = false;
michael@0 533 mLayersUpdated = false;
michael@0 534
michael@0 535 // Apply the render offset
michael@0 536 mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
michael@0 537
michael@0 538 Matrix4x4 transform;
michael@0 539 ToMatrix4x4(gfx3DMatrix(treeTransform), transform);
michael@0 540 transform = transform * aLayer->GetTransform();
michael@0 541
michael@0 542 // GetTransform already takes the pre- and post-scale into account. Since we
michael@0 543 // will apply the pre- and post-scale again when computing the effective
michael@0 544 // transform, we must apply the inverses here.
michael@0 545 transform.Scale(1.0f/container->GetPreXScale(),
michael@0 546 1.0f/container->GetPreYScale(),
michael@0 547 1);
michael@0 548 transform = transform * Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
michael@0 549 1.0f/aLayer->GetPostYScale(),
michael@0 550 1);
michael@0 551 layerComposite->SetShadowTransform(transform);
michael@0 552 NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
michael@0 553 "overwriting animated transform!");
michael@0 554
michael@0 555 // Apply resolution scaling to the old transform - the layer tree as it is
michael@0 556 // doesn't have the necessary transform to display correctly.
michael@0 557 LayoutDeviceToLayerScale resolution = metrics.mCumulativeResolution;
michael@0 558 oldTransform.Scale(resolution.scale, resolution.scale, 1);
michael@0 559
michael@0 560 AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform, fixedLayerMargins);
michael@0 561
michael@0 562 appliedTransform = true;
michael@0 563 }
michael@0 564
michael@0 565 if (container->GetScrollbarDirection() != Layer::NONE) {
michael@0 566 ApplyAsyncTransformToScrollbar(aCurrentFrame, container);
michael@0 567 }
michael@0 568 return appliedTransform;
michael@0 569 }
michael@0 570
michael@0 571 static bool
michael@0 572 LayerHasNonContainerDescendants(ContainerLayer* aContainer)
michael@0 573 {
michael@0 574 for (Layer* child = aContainer->GetFirstChild();
michael@0 575 child; child = child->GetNextSibling()) {
michael@0 576 ContainerLayer* container = child->AsContainerLayer();
michael@0 577 if (!container || LayerHasNonContainerDescendants(container)) {
michael@0 578 return true;
michael@0 579 }
michael@0 580 }
michael@0 581
michael@0 582 return false;
michael@0 583 }
michael@0 584
michael@0 585 static bool
michael@0 586 LayerIsContainerForScrollbarTarget(Layer* aTarget, ContainerLayer* aScrollbar)
michael@0 587 {
michael@0 588 if (!aTarget->AsContainerLayer()) {
michael@0 589 return false;
michael@0 590 }
michael@0 591 AsyncPanZoomController* apzc = aTarget->AsContainerLayer()->GetAsyncPanZoomController();
michael@0 592 if (!apzc) {
michael@0 593 return false;
michael@0 594 }
michael@0 595 const FrameMetrics& metrics = aTarget->AsContainerLayer()->GetFrameMetrics();
michael@0 596 if (metrics.GetScrollId() != aScrollbar->GetScrollbarTargetContainerId()) {
michael@0 597 return false;
michael@0 598 }
michael@0 599 return true;
michael@0 600 }
michael@0 601
michael@0 602 static void
michael@0 603 ApplyAsyncTransformToScrollbarForContent(TimeStamp aCurrentFrame, ContainerLayer* aScrollbar,
michael@0 604 Layer* aContent, bool aScrollbarIsChild)
michael@0 605 {
michael@0 606 ContainerLayer* content = aContent->AsContainerLayer();
michael@0 607 if (!LayerHasNonContainerDescendants(content)) {
michael@0 608 return;
michael@0 609 }
michael@0 610
michael@0 611 const FrameMetrics& metrics = content->GetFrameMetrics();
michael@0 612 AsyncPanZoomController* apzc = content->GetAsyncPanZoomController();
michael@0 613
michael@0 614 if (aScrollbarIsChild) {
michael@0 615 // Because we try to apply the scrollbar transform before we apply the async transform on
michael@0 616 // the actual content, we need to ensure that the APZC has updated any pending animations
michael@0 617 // to the current frame timestamp before we extract the transforms from it. The code in this
michael@0 618 // block accomplishes that and throws away the temp variables.
michael@0 619 // TODO: it might be cleaner to do a pass through the layer tree to advance all the APZC
michael@0 620 // transforms before updating the layer shadow transforms. That will allow removal of this code.
michael@0 621 ViewTransform treeTransform;
michael@0 622 ScreenPoint scrollOffset;
michael@0 623 apzc->SampleContentTransformForFrame(aCurrentFrame, &treeTransform, scrollOffset);
michael@0 624 }
michael@0 625
michael@0 626 gfx3DMatrix asyncTransform = gfx3DMatrix(apzc->GetCurrentAsyncTransform());
michael@0 627 gfx3DMatrix nontransientTransform = apzc->GetNontransientAsyncTransform();
michael@0 628 gfx3DMatrix transientTransform = asyncTransform * nontransientTransform.Inverse();
michael@0 629
michael@0 630 // |transientTransform| represents the amount by which we have scrolled and
michael@0 631 // zoomed since the last paint. Because the scrollbar was sized and positioned based
michael@0 632 // on the painted content, we need to adjust it based on transientTransform so that
michael@0 633 // it reflects what the user is actually seeing now.
michael@0 634 // - The scroll thumb needs to be scaled in the direction of scrolling by the inverse
michael@0 635 // of the transientTransform scale (representing the zoom). This is because zooming
michael@0 636 // in decreases the fraction of the whole scrollable rect that is in view.
michael@0 637 // - It needs to be translated in opposite direction of the transientTransform
michael@0 638 // translation (representing the scroll). This is because scrolling down, which
michael@0 639 // translates the layer content up, should result in moving the scroll thumb down.
michael@0 640 // The amount of the translation to the scroll thumb should be such that the ratio
michael@0 641 // of the translation to the size of the scroll port is the same as the ratio
michael@0 642 // of the scroll amount to the size of the scrollable rect.
michael@0 643 Matrix4x4 scrollbarTransform;
michael@0 644 if (aScrollbar->GetScrollbarDirection() == Layer::VERTICAL) {
michael@0 645 float scale = metrics.CalculateCompositedSizeInCssPixels().height / metrics.mScrollableRect.height;
michael@0 646 scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform.GetYScale(), 1.f);
michael@0 647 scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(0, -transientTransform._42 * scale, 0);
michael@0 648 }
michael@0 649 if (aScrollbar->GetScrollbarDirection() == Layer::HORIZONTAL) {
michael@0 650 float scale = metrics.CalculateCompositedSizeInCssPixels().width / metrics.mScrollableRect.width;
michael@0 651 scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform.GetXScale(), 1.f, 1.f);
michael@0 652 scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(-transientTransform._41 * scale, 0, 0);
michael@0 653 }
michael@0 654
michael@0 655 Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
michael@0 656
michael@0 657 if (aScrollbarIsChild) {
michael@0 658 // If the scrollbar layer is a child of the content it is a scrollbar for, then we
michael@0 659 // need to do an extra untransform to cancel out the transient async transform on
michael@0 660 // the content. This is needed because otherwise that transient async transform is
michael@0 661 // part of the effective transform of this scrollbar, and the scrollbar will jitter
michael@0 662 // as the content scrolls.
michael@0 663 Matrix4x4 targetUntransform;
michael@0 664 ToMatrix4x4(transientTransform.Inverse(), targetUntransform);
michael@0 665 transform = transform * targetUntransform;
michael@0 666 }
michael@0 667
michael@0 668 // GetTransform already takes the pre- and post-scale into account. Since we
michael@0 669 // will apply the pre- and post-scale again when computing the effective
michael@0 670 // transform, we must apply the inverses here.
michael@0 671 transform.Scale(1.0f/aScrollbar->GetPreXScale(),
michael@0 672 1.0f/aScrollbar->GetPreYScale(),
michael@0 673 1);
michael@0 674 transform = transform * Matrix4x4().Scale(1.0f/aScrollbar->GetPostXScale(),
michael@0 675 1.0f/aScrollbar->GetPostYScale(),
michael@0 676 1);
michael@0 677 aScrollbar->AsLayerComposite()->SetShadowTransform(transform);
michael@0 678 }
michael@0 679
michael@0 680 void
michael@0 681 AsyncCompositionManager::ApplyAsyncTransformToScrollbar(TimeStamp aCurrentFrame, ContainerLayer* aLayer)
michael@0 682 {
michael@0 683 // If this layer corresponds to a scrollbar, then there should be a layer that
michael@0 684 // is a previous sibling or a parent that has a matching ViewID on its FrameMetrics.
michael@0 685 // That is the content that this scrollbar is for. We pick up the transient
michael@0 686 // async transform from that layer and use it to update the scrollbar position.
michael@0 687 // Note that it is possible that the content layer is no longer there; in
michael@0 688 // this case we don't need to do anything because there can't be an async
michael@0 689 // transform on the content.
michael@0 690 // We only apply the transform if the scroll-target layer has non-container
michael@0 691 // children (i.e. when it has some possibly-visible content). This is to
michael@0 692 // avoid moving scroll-bars in the situation that only a scroll information
michael@0 693 // layer has been built for a scroll frame, as this would result in a
michael@0 694 // disparity between scrollbars and visible content.
michael@0 695 for (Layer* scrollTarget = aLayer->GetPrevSibling();
michael@0 696 scrollTarget;
michael@0 697 scrollTarget = scrollTarget->GetPrevSibling()) {
michael@0 698 if (LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
michael@0 699 // Found a sibling that matches our criteria
michael@0 700 ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, false);
michael@0 701 return;
michael@0 702 }
michael@0 703 }
michael@0 704
michael@0 705 // If we didn't find a sibling, look for a parent
michael@0 706 Layer* scrollTarget = aLayer->GetParent();
michael@0 707 if (scrollTarget && LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
michael@0 708 ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, true);
michael@0 709 }
michael@0 710 }
michael@0 711
michael@0 712 void
michael@0 713 AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
michael@0 714 {
michael@0 715 LayerComposite* layerComposite = aLayer->AsLayerComposite();
michael@0 716 ContainerLayer* container = aLayer->AsContainerLayer();
michael@0 717
michael@0 718 const FrameMetrics& metrics = container->GetFrameMetrics();
michael@0 719 // We must apply the resolution scale before a pan/zoom transform, so we call
michael@0 720 // GetTransform here.
michael@0 721 gfx3DMatrix currentTransform;
michael@0 722 To3DMatrix(aLayer->GetTransform(), currentTransform);
michael@0 723 Matrix4x4 oldTransform = aLayer->GetTransform();
michael@0 724
michael@0 725 gfx3DMatrix treeTransform;
michael@0 726
michael@0 727 CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel();
michael@0 728
michael@0 729 LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom);
michael@0 730
michael@0 731 if (mIsFirstPaint) {
michael@0 732 mContentRect = metrics.mScrollableRect;
michael@0 733 SetFirstPaintViewport(scrollOffsetLayerPixels,
michael@0 734 geckoZoom,
michael@0 735 mContentRect);
michael@0 736 mIsFirstPaint = false;
michael@0 737 } else if (!metrics.mScrollableRect.IsEqualEdges(mContentRect)) {
michael@0 738 mContentRect = metrics.mScrollableRect;
michael@0 739 SetPageRect(mContentRect);
michael@0 740 }
michael@0 741
michael@0 742 // We synchronise the viewport information with Java after sending the above
michael@0 743 // notifications, so that Java can take these into account in its response.
michael@0 744 // Calculate the absolute display port to send to Java
michael@0 745 LayerIntRect displayPort = RoundedToInt(
michael@0 746 (metrics.mCriticalDisplayPort.IsEmpty()
michael@0 747 ? metrics.mDisplayPort
michael@0 748 : metrics.mCriticalDisplayPort
michael@0 749 ) * geckoZoom);
michael@0 750 displayPort += scrollOffsetLayerPixels;
michael@0 751
michael@0 752 LayerMargin fixedLayerMargins(0, 0, 0, 0);
michael@0 753 ScreenPoint offset(0, 0);
michael@0 754
michael@0 755 // Ideally we would initialize userZoom to AsyncPanZoomController::CalculateResolution(metrics)
michael@0 756 // but this causes a reftest-ipc test to fail (see bug 883646 comment 27). The reason for this
michael@0 757 // appears to be that metrics.mZoom is poorly initialized in some scenarios. In these scenarios,
michael@0 758 // however, we can assume there is no async zooming in progress and so the following statement
michael@0 759 // works fine.
michael@0 760 CSSToScreenScale userZoom(metrics.mDevPixelsPerCSSPixel * metrics.mCumulativeResolution * LayerToScreenScale(1));
michael@0 761 ScreenPoint userScroll = metrics.GetScrollOffset() * userZoom;
michael@0 762 SyncViewportInfo(displayPort, geckoZoom, mLayersUpdated,
michael@0 763 userScroll, userZoom, fixedLayerMargins,
michael@0 764 offset);
michael@0 765 mLayersUpdated = false;
michael@0 766
michael@0 767 // Apply the render offset
michael@0 768 mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
michael@0 769
michael@0 770 // Handle transformations for asynchronous panning and zooming. We determine the
michael@0 771 // zoom used by Gecko from the transformation set on the root layer, and we
michael@0 772 // determine the scroll offset used by Gecko from the frame metrics of the
michael@0 773 // primary scrollable layer. We compare this to the user zoom and scroll
michael@0 774 // offset in the view transform we obtained from Java in order to compute the
michael@0 775 // transformation we need to apply.
michael@0 776 LayerToScreenScale zoomAdjust = userZoom / geckoZoom;
michael@0 777
michael@0 778 LayerPoint geckoScroll(0, 0);
michael@0 779 if (metrics.IsScrollable()) {
michael@0 780 geckoScroll = metrics.GetScrollOffset() * geckoZoom;
michael@0 781 }
michael@0 782
michael@0 783 LayerPoint translation = (userScroll / zoomAdjust) - geckoScroll;
michael@0 784 treeTransform = gfx3DMatrix(ViewTransform(-translation,
michael@0 785 userZoom
michael@0 786 / metrics.mDevPixelsPerCSSPixel
michael@0 787 / metrics.GetParentResolution()));
michael@0 788
michael@0 789 // The transform already takes the resolution scale into account. Since we
michael@0 790 // will apply the resolution scale again when computing the effective
michael@0 791 // transform, we must apply the inverse resolution scale here.
michael@0 792 gfx3DMatrix computedTransform = treeTransform * currentTransform;
michael@0 793 computedTransform.Scale(1.0f/container->GetPreXScale(),
michael@0 794 1.0f/container->GetPreYScale(),
michael@0 795 1);
michael@0 796 computedTransform.ScalePost(1.0f/container->GetPostXScale(),
michael@0 797 1.0f/container->GetPostYScale(),
michael@0 798 1);
michael@0 799 Matrix4x4 matrix;
michael@0 800 ToMatrix4x4(computedTransform, matrix);
michael@0 801 layerComposite->SetShadowTransform(matrix);
michael@0 802 NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
michael@0 803 "overwriting animated transform!");
michael@0 804
michael@0 805 // Apply resolution scaling to the old transform - the layer tree as it is
michael@0 806 // doesn't have the necessary transform to display correctly.
michael@0 807 oldTransform.Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1);
michael@0 808
michael@0 809 // Make sure that overscroll and under-zoom are represented in the old
michael@0 810 // transform so that fixed position content moves and scales accordingly.
michael@0 811 // These calculations will effectively scale and offset fixed position layers
michael@0 812 // in screen space when the compensatory transform is performed in
michael@0 813 // AlignFixedAndStickyLayers.
michael@0 814 ScreenRect contentScreenRect = mContentRect * userZoom;
michael@0 815 gfxPoint3D overscrollTranslation;
michael@0 816 if (userScroll.x < contentScreenRect.x) {
michael@0 817 overscrollTranslation.x = contentScreenRect.x - userScroll.x;
michael@0 818 } else if (userScroll.x + metrics.mCompositionBounds.width > contentScreenRect.XMost()) {
michael@0 819 overscrollTranslation.x = contentScreenRect.XMost() -
michael@0 820 (userScroll.x + metrics.mCompositionBounds.width);
michael@0 821 }
michael@0 822 if (userScroll.y < contentScreenRect.y) {
michael@0 823 overscrollTranslation.y = contentScreenRect.y - userScroll.y;
michael@0 824 } else if (userScroll.y + metrics.mCompositionBounds.height > contentScreenRect.YMost()) {
michael@0 825 overscrollTranslation.y = contentScreenRect.YMost() -
michael@0 826 (userScroll.y + metrics.mCompositionBounds.height);
michael@0 827 }
michael@0 828 oldTransform.Translate(overscrollTranslation.x,
michael@0 829 overscrollTranslation.y,
michael@0 830 overscrollTranslation.z);
michael@0 831
michael@0 832 gfx::Size underZoomScale(1.0f, 1.0f);
michael@0 833 if (mContentRect.width * userZoom.scale < metrics.mCompositionBounds.width) {
michael@0 834 underZoomScale.width = (mContentRect.width * userZoom.scale) /
michael@0 835 metrics.mCompositionBounds.width;
michael@0 836 }
michael@0 837 if (mContentRect.height * userZoom.scale < metrics.mCompositionBounds.height) {
michael@0 838 underZoomScale.height = (mContentRect.height * userZoom.scale) /
michael@0 839 metrics.mCompositionBounds.height;
michael@0 840 }
michael@0 841 oldTransform.Scale(underZoomScale.width, underZoomScale.height, 1);
michael@0 842
michael@0 843 // Make sure fixed position layers don't move away from their anchor points
michael@0 844 // when we're asynchronously panning or zooming
michael@0 845 AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform, fixedLayerMargins);
michael@0 846 }
michael@0 847
michael@0 848 bool
michael@0 849 AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame)
michael@0 850 {
michael@0 851 PROFILER_LABEL("AsyncCompositionManager", "TransformShadowTree");
michael@0 852 Layer* root = mLayerManager->GetRoot();
michael@0 853 if (!root) {
michael@0 854 return false;
michael@0 855 }
michael@0 856
michael@0 857 // NB: we must sample animations *before* sampling pan/zoom
michael@0 858 // transforms.
michael@0 859 bool wantNextFrame = SampleAnimations(root, aCurrentFrame);
michael@0 860
michael@0 861 // FIXME/bug 775437: unify this interface with the ~native-fennec
michael@0 862 // derived code
michael@0 863 //
michael@0 864 // Attempt to apply an async content transform to any layer that has
michael@0 865 // an async pan zoom controller (which means that it is rendered
michael@0 866 // async using Gecko). If this fails, fall back to transforming the
michael@0 867 // primary scrollable layer. "Failing" here means that we don't
michael@0 868 // find a frame that is async scrollable. Note that the fallback
michael@0 869 // code also includes Fennec which is rendered async. Fennec uses
michael@0 870 // its own platform-specific async rendering that is done partially
michael@0 871 // in Gecko and partially in Java.
michael@0 872 if (!ApplyAsyncContentTransformToTree(aCurrentFrame, root, &wantNextFrame)) {
michael@0 873 nsAutoTArray<Layer*,1> scrollableLayers;
michael@0 874 #ifdef MOZ_WIDGET_ANDROID
michael@0 875 scrollableLayers.AppendElement(mLayerManager->GetPrimaryScrollableLayer());
michael@0 876 #else
michael@0 877 mLayerManager->GetScrollableLayers(scrollableLayers);
michael@0 878 #endif
michael@0 879
michael@0 880 for (uint32_t i = 0; i < scrollableLayers.Length(); i++) {
michael@0 881 if (scrollableLayers[i]) {
michael@0 882 TransformScrollableLayer(scrollableLayers[i]);
michael@0 883 }
michael@0 884 }
michael@0 885 }
michael@0 886
michael@0 887 return wantNextFrame;
michael@0 888 }
michael@0 889
michael@0 890 void
michael@0 891 AsyncCompositionManager::SetFirstPaintViewport(const LayerIntPoint& aOffset,
michael@0 892 const CSSToLayerScale& aZoom,
michael@0 893 const CSSRect& aCssPageRect)
michael@0 894 {
michael@0 895 #ifdef MOZ_WIDGET_ANDROID
michael@0 896 AndroidBridge::Bridge()->SetFirstPaintViewport(aOffset, aZoom, aCssPageRect);
michael@0 897 #endif
michael@0 898 }
michael@0 899
michael@0 900 void
michael@0 901 AsyncCompositionManager::SetPageRect(const CSSRect& aCssPageRect)
michael@0 902 {
michael@0 903 #ifdef MOZ_WIDGET_ANDROID
michael@0 904 AndroidBridge::Bridge()->SetPageRect(aCssPageRect);
michael@0 905 #endif
michael@0 906 }
michael@0 907
michael@0 908 void
michael@0 909 AsyncCompositionManager::SyncViewportInfo(const LayerIntRect& aDisplayPort,
michael@0 910 const CSSToLayerScale& aDisplayResolution,
michael@0 911 bool aLayersUpdated,
michael@0 912 ScreenPoint& aScrollOffset,
michael@0 913 CSSToScreenScale& aScale,
michael@0 914 LayerMargin& aFixedLayerMargins,
michael@0 915 ScreenPoint& aOffset)
michael@0 916 {
michael@0 917 #ifdef MOZ_WIDGET_ANDROID
michael@0 918 AndroidBridge::Bridge()->SyncViewportInfo(aDisplayPort,
michael@0 919 aDisplayResolution,
michael@0 920 aLayersUpdated,
michael@0 921 aScrollOffset,
michael@0 922 aScale,
michael@0 923 aFixedLayerMargins,
michael@0 924 aOffset);
michael@0 925 #endif
michael@0 926 }
michael@0 927
michael@0 928 void
michael@0 929 AsyncCompositionManager::SyncFrameMetrics(const ScreenPoint& aScrollOffset,
michael@0 930 float aZoom,
michael@0 931 const CSSRect& aCssPageRect,
michael@0 932 bool aLayersUpdated,
michael@0 933 const CSSRect& aDisplayPort,
michael@0 934 const CSSToLayerScale& aDisplayResolution,
michael@0 935 bool aIsFirstPaint,
michael@0 936 LayerMargin& aFixedLayerMargins,
michael@0 937 ScreenPoint& aOffset)
michael@0 938 {
michael@0 939 #ifdef MOZ_WIDGET_ANDROID
michael@0 940 AndroidBridge::Bridge()->SyncFrameMetrics(aScrollOffset, aZoom, aCssPageRect,
michael@0 941 aLayersUpdated, aDisplayPort,
michael@0 942 aDisplayResolution, aIsFirstPaint,
michael@0 943 aFixedLayerMargins, aOffset);
michael@0 944 #endif
michael@0 945 }
michael@0 946
michael@0 947 } // namespace layers
michael@0 948 } // namespace mozilla

mercurial