diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 5f7a9f11460..f985f37f437 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -610,6 +610,12 @@ ApplyAsyncTransformToScrollbarForContent(TimeStamp aCurrentFrame, ContainerLayer Layer* aContent, bool aScrollbarIsChild) { ContainerLayer* content = aContent->AsContainerLayer(); + + // We only apply the transform if the scroll-target layer has non-container + // children (i.e. when it has some possibly-visible content). This is to + // avoid moving scroll-bars in the situation that only a scroll information + // layer has been built for a scroll frame, as this would result in a + // disparity between scrollbars and visible content. if (!LayerHasNonContainerDescendants(content)) { return; } @@ -683,6 +689,32 @@ ApplyAsyncTransformToScrollbarForContent(TimeStamp aCurrentFrame, ContainerLayer aScrollbar->AsLayerComposite()->SetShadowTransform(transform); } +static Layer* +FindScrolledLayerForScrollbar(ContainerLayer* aLayer, bool* aOutIsAncestor) +{ + // Search all siblings of aLayer and of its ancestors. + for (Layer* ancestor = aLayer; ancestor; ancestor = ancestor->GetParent()) { + for (Layer* scrollTarget = ancestor; + scrollTarget; + scrollTarget = scrollTarget->GetPrevSibling()) { + if (scrollTarget != aLayer && + LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) { + *aOutIsAncestor = (scrollTarget == ancestor); + return scrollTarget; + } + } + for (Layer* scrollTarget = ancestor->GetNextSibling(); + scrollTarget; + scrollTarget = scrollTarget->GetNextSibling()) { + if (LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) { + *aOutIsAncestor = false; + return scrollTarget; + } + } + } + return nullptr; +} + void AsyncCompositionManager::ApplyAsyncTransformToScrollbar(TimeStamp aCurrentFrame, ContainerLayer* aLayer) { @@ -693,25 +725,11 @@ AsyncCompositionManager::ApplyAsyncTransformToScrollbar(TimeStamp aCurrentFrame, // Note that it is possible that the content layer is no longer there; in // this case we don't need to do anything because there can't be an async // transform on the content. - // We only apply the transform if the scroll-target layer has non-container - // children (i.e. when it has some possibly-visible content). This is to - // avoid moving scroll-bars in the situation that only a scroll information - // layer has been built for a scroll frame, as this would result in a - // disparity between scrollbars and visible content. - for (Layer* scrollTarget = aLayer->GetPrevSibling(); - scrollTarget; - scrollTarget = scrollTarget->GetPrevSibling()) { - if (LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) { - // Found a sibling that matches our criteria - ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, false); - return; - } - } - - // If we didn't find a sibling, look for a parent - Layer* scrollTarget = aLayer->GetParent(); - if (scrollTarget && LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) { - ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, true); + bool isAncestor = false; + Layer* scrollTarget = FindScrolledLayerForScrollbar(aLayer, &isAncestor); + if (scrollTarget) { + ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, + isAncestor); } }