Bug 1214151 - If a sticky element does not consume all of the un-adjustment for an async transform, allow a descendant fixed or sticky element to consume it. r=mstange draft
authorBotond Ballo <botond@mozilla.com>
Wed, 29 Jun 2016 18:25:31 -0400
changeset 382588 665b49839be9e7ac337c1c23232c6ec9b140134e
parent 382587 ae9c4ad814d232e44e0b87c50612ee8edc4adcab
child 382589 904694f7b3eeab9dc48b33e126353bf44c5e313c
push id21770
push userbballo@mozilla.com
push dateWed, 29 Jun 2016 22:29:45 +0000
reviewersmstange
bugs1214151
milestone50.0a1
Bug 1214151 - If a sticky element does not consume all of the un-adjustment for an async transform, allow a descendant fixed or sticky element to consume it. r=mstange MozReview-Commit-ID: HHGjs4GZGNX
gfx/layers/composite/AsyncCompositionManager.cpp
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -500,42 +500,57 @@ AsyncCompositionManager::AlignFixedAndSt
         // transform. This translation will apply on top of the layer's local
         // transform, but |anchor| and |transformedAnchor| are in a coordinate space
         // where the local transform isn't applied yet, so apply it and then subtract
         // to get the desired translation.
         auto localTransformTyped = ViewAs<LayerToParentLayerMatrix4x4>(localTransform);
         ParentLayerPoint translation = TransformBy(localTransformTyped, transformedAnchor)
                                      - TransformBy(localTransformTyped, anchor);
 
+        // A fixed layer will "consume" (be unadjusted by) the entire translation
+        // calculated above. A sticky layer may consume all, part, or none of it,
+        // depending on where we are relative to its sticky scroll range.
+        bool translationConsumed = true;
+
         if (layer->GetIsStickyPosition()) {
           // For sticky positioned layers, the difference between the two rectangles
           // defines a pair of translation intervals in each dimension through which
           // the layer should not move relative to the scroll container. To
           // accomplish this, we limit each dimension of the |translation| to that
           // part of it which overlaps those intervals.
           const LayerRect& stickyOuter = layer->GetStickyScrollRangeOuter();
           const LayerRect& stickyInner = layer->GetStickyScrollRangeInner();
 
           // TODO: There's a unit mismatch here, as |translation| is in ParentLayer
           //       space while |stickyOuter| and |stickyInner| are in Layer space.
+          ParentLayerPoint originalTranslation = translation;
           translation.y = IntervalOverlap(translation.y, stickyOuter.y, stickyOuter.YMost()) -
                           IntervalOverlap(translation.y, stickyInner.y, stickyInner.YMost());
           translation.x = IntervalOverlap(translation.x, stickyOuter.x, stickyOuter.XMost()) -
                           IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost());
+          if (translation != originalTranslation) {
+            translationConsumed = false;
+          }
         }
 
         // Finally, apply the translation to the layer transform. Note that in cases
         // where the async transform on |aTransformedSubtreeRoot| affects this layer's
         // clip rect, we need to apply the same translation to said clip rect, so
         // that the effective transform on the clip rect takes it back to where it was
         // originally, had there been no async scroll.
         TranslateShadowLayer(layer, ThebesPoint(translation.ToUnknownPoint()),
             true, aClipPartsCache);
 
-        return TraversalFlag::Skip;
+        // If we didn't consume the entire translation, continue the traversal
+        // to allow a descendant fixed or sticky layer to consume the rest.
+        // TODO: We curently don't handle the case where we consume part but not
+        //       all of the translation correctly. In such a case,
+        //       |a[Previous|Current]TransformForRoot| would need to be adjusted
+        //       to reflect only the unconsumed part of the translation.
+        return translationConsumed ? TraversalFlag::Skip : TraversalFlag::Continue;
       });
 }
 
 static void
 SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart,
             StyleAnimationValue& aEnd, Animatable* aValue, Layer* aLayer)
 {
   StyleAnimationValue interpolatedValue;