diff --git a/gfx/layers/wr/ScrollingLayersHelper.cpp b/gfx/layers/wr/ScrollingLayersHelper.cpp index 69d48764e75f..fa65e16a1bfb 100644 --- a/gfx/layers/wr/ScrollingLayersHelper.cpp +++ b/gfx/layers/wr/ScrollingLayersHelper.cpp @@ -184,6 +184,26 @@ ScrollingLayersHelper::RecurseAndDefineClip(nsDisplayItem* aItem, // than aChain->mParent. ancestorIds.second = Nothing(); } + } else { + MOZ_ASSERT(!ancestorIds.second); + // If aChain->mASR is already the topmost scroll layer on the stack, but + // but there was another clip pushed *on top* of that ASR, then that clip + // shares the ASR, and we need to make our clip a child of that clip, which + // in turn will already be a descendant of the correct ASR. + // This covers the cases where e.g. the Gecko display list has nested items, + // and the clip chain on the nested item implicitly extends from the clip + // chain on the containing wrapper item. In this case the aChain->mParent + // pointer will be null for the nested item but the containing wrapper's + // clip will be on the stack already and we can pick it up from there. + // Another way of thinking about this is that if the clip chain were + // "fully completed" then aChain->mParent wouldn't be null but would point + // to the clip corresponding to mBuilder->TopmostClipId(), and we would + // have gone into the |aChain->mParent->mASR == aAsr| branch above. + FrameMetrics::ViewID scrollId = aChain->mASR ? nsLayoutUtils::ViewIDForASR(aChain->mASR) : FrameMetrics::NULL_SCROLL_ID; + if (mBuilder->TopmostScrollId() == scrollId && mBuilder->TopmostIsClip()) { + ancestorIds.first = Nothing(); + ancestorIds.second = mBuilder->TopmostClipId(); + } } // At most one of the ancestor pair should be defined here, and the one that // is defined will be the parent clip for the new clip that we're defining. diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp index ca0454bb8f03..ff4ca533fe2e 100644 --- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -1169,5 +1169,14 @@ DisplayListBuilder::TopmostScrollId() return layers::FrameMetrics::NULL_SCROLL_ID; } +bool +DisplayListBuilder::TopmostIsClip() +{ + if (mClipStack.empty()) { + return false; + } + return mClipStack.back().is(); +} + } // namespace wr } // namespace mozilla diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h index 98445f5ee516..dfe10c14ffcc 100644 --- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -405,6 +405,8 @@ public: Maybe TopmostClipId(); // Same as TopmostClipId() but for scroll layers. layers::FrameMetrics::ViewID TopmostScrollId(); + // If the topmost item on the stack is a clip or a scroll layer + bool TopmostIsClip(); // Try to avoid using this when possible. wr::WrState* Raw() { return mWrState; }