--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -229,18 +229,18 @@ EXPORTS.mozilla.layers += [
'SourceSurfaceSharedData.h',
'SourceSurfaceVolatileData.h',
'SyncObject.h',
'TextureSourceProvider.h',
'TextureWrapperImage.h',
'TransactionIdAllocator.h',
'UpdateImageHelper.h',
'wr/AsyncImagePipelineManager.h',
+ 'wr/ClipManager.h',
'wr/IpcResourceUpdateQueue.h',
- 'wr/ScrollingLayersHelper.h',
'wr/StackingContextHelper.h',
'wr/WebRenderBridgeChild.h',
'wr/WebRenderBridgeParent.h',
'wr/WebRenderCanvasRenderer.h',
'wr/WebRenderCommandBuilder.h',
'wr/WebRenderDrawEventRecorder.h',
'wr/WebRenderImageHost.h',
'wr/WebRenderLayerManager.h',
@@ -468,18 +468,18 @@ UNIFIED_SOURCES += [
'RotatedBuffer.cpp',
'ShareableCanvasRenderer.cpp',
'SourceSurfaceSharedData.cpp',
'SourceSurfaceVolatileData.cpp',
'SyncObject.cpp',
'TextureSourceProvider.cpp',
'TextureWrapperImage.cpp',
'wr/AsyncImagePipelineManager.cpp',
+ 'wr/ClipManager.cpp',
'wr/IpcResourceUpdateQueue.cpp',
- 'wr/ScrollingLayersHelper.cpp',
'wr/StackingContextHelper.cpp',
'wr/WebRenderBridgeChild.cpp',
'wr/WebRenderBridgeParent.cpp',
'wr/WebRenderCanvasRenderer.cpp',
'wr/WebRenderCommandBuilder.cpp',
'wr/WebRenderDrawEventRecorder.cpp',
'wr/WebRenderImageHost.cpp',
'wr/WebRenderLayerManager.cpp',
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/ClipManager.cpp
@@ -0,0 +1,407 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/layers/ClipManager.h"
+
+#include "DisplayItemClipChain.h"
+#include "FrameMetrics.h"
+#include "LayersLogging.h"
+#include "mozilla/layers/StackingContextHelper.h"
+#include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+#include "nsDisplayList.h"
+#include "UnitTransforms.h"
+
+#define CLIP_LOG(...)
+//#define CLIP_LOG(...) printf_stderr("CLIP: " __VA_ARGS__)
+//#define CLIP_LOG(...) if (XRE_IsContentProcess()) printf_stderr("CLIP: " __VA_ARGS__)
+
+namespace mozilla {
+namespace layers {
+
+ClipManager::ClipManager()
+ : mManager(nullptr)
+ , mBuilder(nullptr)
+{
+}
+
+void
+ClipManager::BeginBuild(WebRenderLayerManager* aManager,
+ wr::DisplayListBuilder& aBuilder)
+{
+ MOZ_ASSERT(!mManager);
+ mManager = aManager;
+ MOZ_ASSERT(!mBuilder);
+ mBuilder = &aBuilder;
+ MOZ_ASSERT(mCacheStack.empty());
+ mCacheStack.emplace();
+ MOZ_ASSERT(mASROverride.empty());
+ MOZ_ASSERT(mItemClipStack.empty());
+}
+
+void
+ClipManager::EndBuild()
+{
+ mBuilder = nullptr;
+ mManager = nullptr;
+ mCacheStack.pop();
+ MOZ_ASSERT(mCacheStack.empty());
+ MOZ_ASSERT(mASROverride.empty());
+ MOZ_ASSERT(mItemClipStack.empty());
+}
+
+void
+ClipManager::BeginList(const StackingContextHelper& aStackingContext)
+{
+ if (aStackingContext.AffectsClipPositioning()) {
+ PushOverrideForASR(
+ mItemClipStack.empty() ? nullptr : mItemClipStack.top().mASR,
+ Nothing());
+ }
+
+ ItemClips clips(nullptr, nullptr);
+ if (!mItemClipStack.empty()) {
+ clips.CopyOutputsFrom(mItemClipStack.top());
+ }
+ mItemClipStack.push(clips);
+}
+
+void
+ClipManager::EndList(const StackingContextHelper& aStackingContext)
+{
+ MOZ_ASSERT(!mItemClipStack.empty());
+ mItemClipStack.top().Unapply(mBuilder);
+ mItemClipStack.pop();
+
+ if (aStackingContext.AffectsClipPositioning()) {
+ PopOverrideForASR(
+ mItemClipStack.empty() ? nullptr : mItemClipStack.top().mASR);
+ }
+}
+
+void
+ClipManager::PushOverrideForASR(const ActiveScrolledRoot* aASR,
+ const Maybe<wr::WrClipId>& aClipId)
+{
+ layers::FrameMetrics::ViewID viewId = aASR
+ ? aASR->GetViewId() : layers::FrameMetrics::NULL_SCROLL_ID;
+ Maybe<wr::WrClipId> scrollId = mBuilder->GetScrollIdForDefinedScrollLayer(viewId);
+ MOZ_ASSERT(scrollId.isSome());
+
+ CLIP_LOG("Pushing override %" PRIu64 " -> %s\n", scrollId->id,
+ aClipId ? Stringify(aClipId->id).c_str() : "(none)");
+ auto it = mASROverride.insert({ *scrollId, std::stack<Maybe<wr::WrClipId>>() });
+ it.first->second.push(aClipId);
+
+ // Start a new cache
+ mCacheStack.emplace();
+}
+
+void
+ClipManager::PopOverrideForASR(const ActiveScrolledRoot* aASR)
+{
+ MOZ_ASSERT(!mCacheStack.empty());
+ mCacheStack.pop();
+
+ layers::FrameMetrics::ViewID viewId = aASR
+ ? aASR->GetViewId() : layers::FrameMetrics::NULL_SCROLL_ID;
+ Maybe<wr::WrClipId> scrollId = mBuilder->GetScrollIdForDefinedScrollLayer(viewId);
+ MOZ_ASSERT(scrollId.isSome());
+
+ auto it = mASROverride.find(*scrollId);
+ MOZ_ASSERT(it != mASROverride.end());
+ MOZ_ASSERT(!(it->second.empty()));
+ CLIP_LOG("Popping override %" PRIu64 " -> %s\n", scrollId->id,
+ it->second.top() ? Stringify(it->second.top()->id).c_str() : "(none)");
+ it->second.pop();
+ if (it->second.empty()) {
+ mASROverride.erase(it);
+ }
+}
+
+Maybe<wr::WrClipId>
+ClipManager::ClipIdAfterOverride(const Maybe<wr::WrClipId>& aClipId)
+{
+ if (!aClipId) {
+ return Nothing();
+ }
+ auto it = mASROverride.find(*aClipId);
+ if (it == mASROverride.end()) {
+ return aClipId;
+ }
+ MOZ_ASSERT(!it->second.empty());
+ CLIP_LOG("Overriding %" PRIu64 " with %s\n", aClipId->id,
+ it->second.top() ? Stringify(it->second.top()->id).c_str() : "(none)");
+ return it->second.top();
+}
+
+void
+ClipManager::BeginItem(nsDisplayItem* aItem,
+ const StackingContextHelper& aStackingContext)
+{
+ CLIP_LOG("processing item %p\n", aItem);
+
+ const DisplayItemClipChain* clip = aItem->GetClipChain();
+ const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot();
+
+ ItemClips clips(asr, clip);
+ MOZ_ASSERT(!mItemClipStack.empty());
+ if (clips.HasSameInputs(mItemClipStack.top())) {
+ // Early-exit because if the clips are the same as aItem's previous sibling,
+ // then we don't need to do do the work of popping the old stuff and then
+ // pushing it right back on for the new item. Note that if aItem doesn't
+ // have a previous sibling, that means BeginList would have been called
+ // just before this, which will have pushed a ItemClips(nullptr, nullptr)
+ // onto mItemClipStack, so the HasSameInputs check should return false.
+ CLIP_LOG("early-exit for %p\n", aItem);
+ return;
+ }
+ // Pop aItem's previous sibling's stuff from mBuilder in preparation for
+ // pushing aItem's stuff.
+ mItemClipStack.top().Unapply(mBuilder);
+ mItemClipStack.pop();
+
+ // Zoom display items report their bounds etc using the parent document's
+ // APD because zoom items act as a conversion layer between the two different
+ // APDs.
+ int32_t auPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
+ if (aItem->GetType() == DisplayItemType::TYPE_ZOOM) {
+ auPerDevPixel = static_cast<nsDisplayZoom*>(aItem)->GetParentAppUnitsPerDevPixel();
+ }
+
+ // There are two ASR chains here that we need to be fully defined. One is the
+ // ASR chain pointed to by |asr|. The other is the
+ // ASR chain pointed to by clip->mASR. We pick the leafmost
+ // of these two chains because that one will include the other. Calling
+ // DefineScrollLayers with this leafmost ASR will recursively define all the
+ // ASRs that we care about for this item, but will not actually push
+ // anything onto the WR stack.
+ const ActiveScrolledRoot* leafmostASR = asr;
+ if (clip) {
+ leafmostASR = ActiveScrolledRoot::PickDescendant(leafmostASR, clip->mASR);
+ }
+ Maybe<wr::WrClipId> leafmostId = DefineScrollLayers(leafmostASR, aItem, aStackingContext);
+
+ // Define all the clips in the item's clip chain, and obtain a clip chain id
+ // for it.
+ clips.mClipChainId = DefineClipChain(clip, auPerDevPixel, aStackingContext);
+
+ if (clip && clip->mASR == asr) {
+ // If the clip's ASR is the same as the item's ASR, then we want to use
+ // the clip as the "scrollframe" for the item, as WR will do the right thing
+ // when building the ClipScrollTree and ensure the item scrolls with the
+ // ASR. Note in particular that we don't want to use scroll id of |asr| here
+ // because we might have a situation where there is a stacking context
+ // between |asr| and |aItem|, and if we used |asr|'s scroll id, then WR
+ // would effectively hoist the item out of the stacking context and attach
+ // it directly to |asr|. This can produce incorrect results. Using the clip
+ // instead of the ASR is strictly better because the clip is usually defined
+ // inside the stacking context, and so the item also stays "inside" the
+ // stacking context rather than geting hoisted out. Note that there might
+ // be cases where the clip is also "outside" the stacking context and in
+ // theory that situation might not be handled correctly, but I haven't seen
+ // it in practice so far.
+ const ClipIdMap& cache = mCacheStack.top();
+ auto it = cache.find(clip);
+ MOZ_ASSERT(it != cache.end());
+ clips.mScrollId = Some(it->second);
+ } else if (clip) {
+ // If the clip's ASR is different, then we need to set the scroll id
+ // explicitly to match the desired ASR.
+ FrameMetrics::ViewID viewId = asr
+ ? asr->GetViewId()
+ : FrameMetrics::NULL_SCROLL_ID;
+ Maybe<wr::WrClipId> scrollId =
+ mBuilder->GetScrollIdForDefinedScrollLayer(viewId);
+ MOZ_ASSERT(scrollId.isSome());
+ clips.mScrollId = scrollId;
+ } else {
+ // If we don't have a clip at all, then we don't want to explicitly push
+ // the ASR either, because as with the first clause of this if condition,
+ // the item might get hoisted out of a stacking context that was pushed
+ // between the |asr| and this |aItem|. Instead we just leave clips.mScrollId
+ // empty and things seem to work out.
+ // XXX: there might be cases where things don't just "work out", in which
+ // case we might need to do something smarter here.
+ }
+
+ // Now that we have the scroll id and a clip id for the item, push it onto
+ // the WR stack.
+ clips.Apply(mBuilder);
+ mItemClipStack.push(clips);
+
+ CLIP_LOG("done setup for %p\n", aItem);
+}
+
+Maybe<wr::WrClipId>
+ClipManager::DefineScrollLayers(const ActiveScrolledRoot* aASR,
+ nsDisplayItem* aItem,
+ const StackingContextHelper& aSc)
+{
+ if (!aASR) {
+ // Recursion base case
+ return Nothing();
+ }
+ FrameMetrics::ViewID viewId = aASR->GetViewId();
+ Maybe<wr::WrClipId> scrollId = mBuilder->GetScrollIdForDefinedScrollLayer(viewId);
+ if (scrollId) {
+ // If we've already defined this scroll layer before, we can early-exit
+ return scrollId;
+ }
+ // Recurse to define the ancestors
+ Maybe<wr::WrClipId> ancestorScrollId = DefineScrollLayers(aASR->mParent, aItem, aSc);
+
+ Maybe<ScrollMetadata> metadata = aASR->mScrollableFrame->ComputeScrollMetadata(
+ mManager, aItem->ReferenceFrame(), ContainerLayerParameters(), nullptr);
+ MOZ_ASSERT(metadata);
+ FrameMetrics& metrics = metadata->GetMetrics();
+
+ if (!metrics.IsScrollable()) {
+ // This item is a scrolling no-op, skip over it in the ASR chain.
+ return ancestorScrollId;
+ }
+
+ LayoutDeviceRect contentRect =
+ metrics.GetExpandedScrollableRect() * metrics.GetDevPixelsPerCSSPixel();
+ LayoutDeviceRect clipBounds =
+ LayoutDeviceRect::FromUnknownRect(metrics.GetCompositionBounds().ToUnknownRect());
+ // The content rect that we hand to PushScrollLayer should be relative to
+ // the same origin as the clipBounds that we hand to PushScrollLayer - that
+ // is, both of them should be relative to the stacking context `aSc`.
+ // However, when we get the scrollable rect from the FrameMetrics, the origin
+ // has nothing to do with the position of the frame but instead represents
+ // the minimum allowed scroll offset of the scrollable content. While APZ
+ // uses this to clamp the scroll position, we don't need to send this to
+ // WebRender at all. Instead, we take the position from the composition
+ // bounds.
+ contentRect.MoveTo(clipBounds.TopLeft());
+
+ Maybe<wr::WrClipId> parent = ClipIdAfterOverride(ancestorScrollId);
+ scrollId = Some(mBuilder->DefineScrollLayer(viewId, parent,
+ wr::ToRoundedLayoutRect(contentRect),
+ wr::ToRoundedLayoutRect(clipBounds)));
+
+ return scrollId;
+}
+
+Maybe<wr::WrClipChainId>
+ClipManager::DefineClipChain(const DisplayItemClipChain* aChain,
+ int32_t aAppUnitsPerDevPixel,
+ const StackingContextHelper& aSc)
+{
+ nsTArray<wr::WrClipId> clipIds;
+ // Iterate through the clips in the current item's clip chain, define them
+ // in WR, and put their IDs into |clipIds|.
+ for (const DisplayItemClipChain* chain = aChain; chain; chain = chain->mParent) {
+ ClipIdMap& cache = mCacheStack.top();
+ auto it = cache.find(chain);
+ if (it != cache.end()) {
+ // Found it in the currently-active cache, so just use the id we have for
+ // it.
+ CLIP_LOG("cache[%p] => %" PRIu64 "\n", chain, it->second.id);
+ clipIds.AppendElement(it->second);
+ continue;
+ }
+ if (!chain->mClip.HasClip()) {
+ // This item in the chain is a no-op, skip over it
+ continue;
+ }
+
+ LayoutDeviceRect clip = LayoutDeviceRect::FromAppUnits(
+ chain->mClip.GetClipRect(), aAppUnitsPerDevPixel);
+ nsTArray<wr::ComplexClipRegion> wrRoundedRects;
+ chain->mClip.ToComplexClipRegions(aAppUnitsPerDevPixel, aSc, wrRoundedRects);
+
+ FrameMetrics::ViewID viewId = chain->mASR
+ ? chain->mASR->GetViewId()
+ : FrameMetrics::NULL_SCROLL_ID;
+ Maybe<wr::WrClipId> scrollId =
+ mBuilder->GetScrollIdForDefinedScrollLayer(viewId);
+ // Before calling DefineClipChain we defined the ASRs by calling
+ // DefineScrollLayers, so we must have a scrollId here.
+ MOZ_ASSERT(scrollId.isSome());
+
+ // Define the clip
+ Maybe<wr::WrClipId> parent = ClipIdAfterOverride(scrollId);
+ wr::WrClipId clipId = mBuilder->DefineClip(
+ parent,
+ wr::ToRoundedLayoutRect(clip), &wrRoundedRects);
+ clipIds.AppendElement(clipId);
+ cache[chain] = clipId;
+ CLIP_LOG("cache[%p] <= %" PRIu64 "\n", chain, clipId.id);
+ }
+
+ // Now find the parent display item's clipchain id
+ Maybe<wr::WrClipChainId> parentChainId;
+ if (!mItemClipStack.empty()) {
+ parentChainId = mItemClipStack.top().mClipChainId;
+ }
+
+ // And define the current display item's clipchain using the clips and the
+ // parent. If the current item has no clips of its own, just use the parent
+ // item's clipchain.
+ Maybe<wr::WrClipChainId> chainId;
+ if (clipIds.Length() > 0) {
+ chainId = Some(mBuilder->DefineClipChain(parentChainId, clipIds));
+ } else {
+ chainId = parentChainId;
+ }
+ return chainId;
+}
+
+ClipManager::~ClipManager()
+{
+ MOZ_ASSERT(!mBuilder);
+ MOZ_ASSERT(mCacheStack.empty());
+ MOZ_ASSERT(mItemClipStack.empty());
+}
+
+ClipManager::ItemClips::ItemClips(const ActiveScrolledRoot* aASR,
+ const DisplayItemClipChain* aChain)
+ : mASR(aASR)
+ , mChain(aChain)
+ , mApplied(false)
+{
+}
+
+void
+ClipManager::ItemClips::Apply(wr::DisplayListBuilder* aBuilder)
+{
+ MOZ_ASSERT(!mApplied);
+ mApplied = true;
+ if (mScrollId) {
+ aBuilder->PushClipAndScrollInfo(*mScrollId,
+ mClipChainId.ptrOr(nullptr));
+ }
+}
+
+void
+ClipManager::ItemClips::Unapply(wr::DisplayListBuilder* aBuilder)
+{
+ if (mApplied) {
+ mApplied = false;
+ if (mScrollId) {
+ aBuilder->PopClipAndScrollInfo();
+ }
+ }
+}
+
+bool
+ClipManager::ItemClips::HasSameInputs(const ItemClips& aOther)
+{
+ return mASR == aOther.mASR &&
+ mChain == aOther.mChain;
+}
+
+void
+ClipManager::ItemClips::CopyOutputsFrom(const ItemClips& aOther)
+{
+ mScrollId = aOther.mScrollId;
+ mClipChainId = aOther.mClipChainId;
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/ClipManager.h
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_CLIPMANAGER_H
+#define GFX_CLIPMANAGER_H
+
+#include <stack>
+#include <unordered_map>
+
+#include "mozilla/Attributes.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+
+class nsDisplayItem;
+
+namespace mozilla {
+
+struct ActiveScrolledRoot;
+struct DisplayItemClipChain;
+
+namespace wr {
+class DisplayListBuilder;
+}
+
+namespace layers {
+
+class StackingContextHelper;
+class WebRenderLayerManager;
+
+/**
+ * This class manages creating and assigning scroll layers and clips in WebRender
+ * based on the gecko display list. It has a few public functions that are
+ * intended to be invoked while traversing the Gecko display list, and it uses
+ * the ASR and clip information from the display list to create the necessary
+ * clip state in WebRender.
+ *
+ * The structure of the clip state in WebRender ends up quite similar to how
+ * it is in Gecko. For each ASR in Gecko, we create a scroll layer (i.e. a
+ * scrolling clip) in WebRender; these form a tree structure similar to the
+ * ASR tree structure. Ancestors of scroll layers are always other scroll
+ * layers, or the root scroll node.
+ * The DisplayItemClipChain list of clips from the gecko display list is
+ * converted to a WR clip chain and pushed on the stack prior to creating
+ * any WR commands for that item, and is popped afterwards. In addition,
+ * the WR clip chain has a parent pointer, which points to the clip chain for
+ * any enclosing stacking context. This again results in a strucuture very
+ * similar to that in Gecko, where the clips from container display items get
+ * applied to the contained display items.
+ */
+class ClipManager
+{
+public:
+ ClipManager();
+
+ void BeginBuild(WebRenderLayerManager* aManager,
+ wr::DisplayListBuilder& aBuilder);
+ void EndBuild();
+
+ void BeginList(const StackingContextHelper& aStackingContext);
+ void EndList(const StackingContextHelper& aStackingContext);
+
+ void BeginItem(nsDisplayItem* aItem,
+ const StackingContextHelper& aStackingContext);
+ ~ClipManager();
+
+ void PushOverrideForASR(const ActiveScrolledRoot* aASR,
+ const Maybe<wr::WrClipId>& aClipId);
+ void PopOverrideForASR(const ActiveScrolledRoot* aASR);
+
+private:
+ Maybe<wr::WrClipId> ClipIdAfterOverride(const Maybe<wr::WrClipId>& aClipId);
+
+ Maybe<wr::WrClipId>
+ DefineScrollLayers(const ActiveScrolledRoot* aASR,
+ nsDisplayItem* aItem,
+ const StackingContextHelper& aSc);
+
+ Maybe<wr::WrClipChainId>
+ DefineClipChain(const DisplayItemClipChain* aChain,
+ int32_t aAppUnitsPerDevPixel,
+ const StackingContextHelper& aSc);
+
+ WebRenderLayerManager* MOZ_NON_OWNING_REF mManager;
+ wr::DisplayListBuilder* mBuilder;
+
+ // Stack of clip caches. Each cache contains a map from gecko
+ // DisplayItemClipChain objects to webrender WrClipIds, which allows us to
+ // avoid redefining identical clips in WR. However, the gecko
+ // DisplayItemClipChain items get deduplicated quite aggressively, without
+ // regard to things like the enclosing reference frame or mask. On the WR
+ // side, we cannot deduplicate clips that aggressively. So what we do is
+ // any time we enter a new reference frame (for example) we create a new clip
+ // cache on mCacheStack. This ensures we continue caching stuff within a given
+ // reference frame, but disallow caching stuff across reference frames. In
+ // general we need to do this anytime PushOverrideForASR is called, as that is
+ // called for the same set of conditions for which we cannot deduplicate clips.
+ typedef std::unordered_map<const DisplayItemClipChain*, wr::WrClipId> ClipIdMap;
+ std::stack<ClipIdMap> mCacheStack;
+
+ // A map that holds the cache overrides created by (a) "out of band" clips,
+ // i.e. clips that are generated by display items but that ClipManager
+ // doesn't know about and (b) stacking contexts that affect clip positioning.
+ // These are called "cache overrides" because while we're inside these things,
+ // we cannot use the ASR from the gecko display list as-is. Fundamentally this
+ // results from a mismatch between the ASR+clip items on the gecko side and
+ // the ClipScrollTree on the WR side; the WR side incorporates things like
+ // transforms and stacking context origins while the gecko side manages those
+ // differently.
+ // Any time ClipManager wants to define a new clip as a child of ASR X, it
+ // should first check the cache overrides to see if there is a cache override
+ // item ((a) or (b) above) that is already a child of X, and then define that
+ // clip as a child of Y instead. This map stores X -> Y, which allows
+ // ClipManager to do the necessary lookup. Note that there theoretically might
+ // be multiple different "Y" clips (in case of nested cache overrides), which
+ // is why we need a stack.
+ std::unordered_map<wr::WrClipId,
+ std::stack<Maybe<wr::WrClipId>>,
+ wr::WrClipId::HashFn> mASROverride;
+
+ // This holds some clip state for a single nsDisplayItem
+ struct ItemClips {
+ ItemClips(const ActiveScrolledRoot* aASR,
+ const DisplayItemClipChain* aChain);
+
+ // These are the "inputs" - they come from the nsDisplayItem
+ const ActiveScrolledRoot* mASR;
+ const DisplayItemClipChain* mChain;
+
+ // These are the "outputs" - they are pushed to WR as needed
+ Maybe<wr::WrClipId> mScrollId;
+ Maybe<wr::WrClipChainId> mClipChainId;
+
+ // State tracking
+ bool mApplied;
+
+ void Apply(wr::DisplayListBuilder* aBuilder);
+ void Unapply(wr::DisplayListBuilder* aBuilder);
+ bool HasSameInputs(const ItemClips& aOther);
+ void CopyOutputsFrom(const ItemClips& aOther);
+ };
+
+ // A stack of ItemClips corresponding to the nsDisplayItem ancestry. Each
+ // time we recurse into a nsDisplayItem's child list, this stack size
+ // increases by one. The topmost item on the stack is for the display item
+ // we are currently processing and items deeper on the stack are for that
+ // display item's ancestors.
+ std::stack<ItemClips> mItemClipStack;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
deleted file mode 100644
--- a/gfx/layers/wr/ScrollingLayersHelper.cpp
+++ /dev/null
@@ -1,597 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/layers/ScrollingLayersHelper.h"
-
-#include "DisplayItemClipChain.h"
-#include "FrameMetrics.h"
-#include "mozilla/layers/StackingContextHelper.h"
-#include "mozilla/layers/WebRenderLayerManager.h"
-#include "mozilla/webrender/WebRenderAPI.h"
-#include "nsDisplayList.h"
-#include "UnitTransforms.h"
-
-#define SLH_LOG(...)
-//#define SLH_LOG(...) printf_stderr("SLH: " __VA_ARGS__)
-//#define SLH_LOG(...) if (XRE_IsContentProcess()) printf_stderr("SLH: " __VA_ARGS__)
-
-namespace mozilla {
-namespace layers {
-
-ScrollingLayersHelper::ScrollingLayersHelper()
- : mManager(nullptr)
- , mBuilder(nullptr)
-{
-}
-
-void
-ScrollingLayersHelper::BeginBuild(WebRenderLayerManager* aManager,
- wr::DisplayListBuilder& aBuilder)
-{
- MOZ_ASSERT(!mManager);
- mManager = aManager;
- MOZ_ASSERT(!mBuilder);
- mBuilder = &aBuilder;
- MOZ_ASSERT(mCacheStack.empty());
- mCacheStack.emplace_back();
- MOZ_ASSERT(mItemClipStack.empty());
-}
-
-void
-ScrollingLayersHelper::EndBuild()
-{
- mBuilder = nullptr;
- mManager = nullptr;
- mCacheStack.pop_back();
- MOZ_ASSERT(mCacheStack.empty());
- MOZ_ASSERT(mItemClipStack.empty());
-}
-
-void
-ScrollingLayersHelper::BeginList(const StackingContextHelper& aStackingContext)
-{
- if (aStackingContext.AffectsClipPositioning()) {
- mCacheStack.emplace_back();
- }
- mItemClipStack.emplace_back(nullptr, nullptr);
-}
-
-void
-ScrollingLayersHelper::EndList(const StackingContextHelper& aStackingContext)
-{
- MOZ_ASSERT(!mItemClipStack.empty());
- mItemClipStack.back().Unapply(mBuilder);
- mItemClipStack.pop_back();
- if (aStackingContext.AffectsClipPositioning()) {
- mCacheStack.pop_back();
- }
-}
-
-void
-ScrollingLayersHelper::BeginItem(nsDisplayItem* aItem,
- const StackingContextHelper& aStackingContext)
-{
- SLH_LOG("processing item %p\n", aItem);
-
- const DisplayItemClipChain* clip = aItem->GetClipChain();
- clip = ExtendChain(clip);
-
- ItemClips clips(aItem->GetActiveScrolledRoot(), clip);
- MOZ_ASSERT(!mItemClipStack.empty());
- if (clips.HasSameInputs(mItemClipStack.back())) {
- // Early-exit because if the clips are the same then we don't need to do
- // do the work of popping the old stuff and then pushing it right back on
- // for the new item.
- SLH_LOG("early-exit for %p\n", aItem);
- return;
- }
- mItemClipStack.back().Unapply(mBuilder);
- mItemClipStack.pop_back();
-
- // Zoom display items report their bounds etc using the parent document's
- // APD because zoom items act as a conversion layer between the two different
- // APDs.
- int32_t auPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
- if (aItem->GetType() == DisplayItemType::TYPE_ZOOM) {
- auPerDevPixel = static_cast<nsDisplayZoom*>(aItem)->GetParentAppUnitsPerDevPixel();
- }
-
- // There are two ASR chains here that we need to be fully defined. One is the
- // ASR chain pointed to by aItem->GetActiveScrolledRoot(). The other is the
- // ASR chain pointed to by clip->mASR. We pick the leafmost
- // of these two chains because that one will include the other.
- // The leafmost clip is trivially going to be |clip|.
- // So we call DefineClipChain with these two leafmost things, and it will
- // recursively define all the clips and scroll layers with the appropriate
- // parents, but will not actually push anything onto the WR stack.
- const ActiveScrolledRoot* leafmostASR = aItem->GetActiveScrolledRoot();
- if (clip) {
- leafmostASR = ActiveScrolledRoot::PickDescendant(leafmostASR, clip->mASR);
- }
- auto ids = DefineClipChain(aItem, leafmostASR, clip,
- auPerDevPixel, aStackingContext);
-
- // Now that stuff is defined, we need to ensure the right items are on the
- // stack. We need this primarily for the WR display items that will be
- // generated while processing aItem. However those display items only care
- // about the topmost clip on the stack. If that were all we cared about we
- // would only need to push one thing here and we would be done. However, we
- // also care about the ScrollingLayersHelper instance that might be created
- // for nested display items, in the case where aItem is a wrapper item. The
- // nested ScrollingLayersHelper may rely on things like TopmostScrollId and
- // TopmostClipId, so now we need to push at most two things onto the stack.
-
- wr::WrScrollId rootId = wr::WrScrollId::RootScrollNode();
- wr::WrScrollId leafmostId = ids.first.valueOr(rootId);
-
- FrameMetrics::ViewID viewId = aItem->GetActiveScrolledRoot()
- ? aItem->GetActiveScrolledRoot()->GetViewId()
- : FrameMetrics::NULL_SCROLL_ID;
- wr::WrScrollId scrollId =
- mBuilder->GetScrollIdForDefinedScrollLayer(viewId).valueOr(rootId);
-
- // If the leafmost ASR is not the same as the item's ASR then we are dealing
- // with a case where the item's clip chain is scrolled by something other than
- // the item's ASR. So for those cases we need to use the ClipAndScroll API.
- bool needClipAndScroll = (leafmostId != scrollId);
-
- // The other scenario where we need to push a ClipAndScroll is when we are
- // in a nested display item where the enclosing item pushed a ClipAndScroll,
- // and our clip chain extends from that item's clip chain. To check this we
- // want to make sure that (a) we are inside a ClipAndScroll, and (b) nothing
- // else was pushed onto mBuilder's stack since that ClipAndScroll.
- if (!needClipAndScroll &&
- mBuilder->TopmostScrollId() == scrollId &&
- !mBuilder->TopmostIsClip()) {
- if (auto cs = EnclosingClipAndScroll()) {
- MOZ_ASSERT(cs->first == scrollId);
- needClipAndScroll = true;
- }
- }
-
- // If we don't need a ClipAndScroll, ensure the item's ASR is at the top of
- // the scroll stack
- if (!needClipAndScroll && mBuilder->TopmostScrollId() != scrollId) {
- MOZ_ASSERT(leafmostId == scrollId); // because !needClipAndScroll
- clips.mScrollId = Some(scrollId);
- }
- // And ensure the leafmost clip, if scrolled by that ASR, is at the top of the
- // stack.
- if (ids.second && clip->mASR == leafmostASR) {
- clips.mClipId = ids.second;
- }
- // If we need the ClipAndScroll, we want to replace the topmost scroll layer
- // with the item's ASR but preseve the topmost clip (which is scrolled by
- // some other ASR).
- if (needClipAndScroll) {
- // If mClipId is set that means we want to push it such that it's going
- // to be the TopmostClipId(), but we haven't actually pushed it yet.
- // But we still want to take that instead of the actual current TopmostClipId().
- Maybe<wr::WrClipId> clipId = clips.mClipId;
- if (!clipId) {
- clipId = mBuilder->TopmostClipId();
- }
-
- clips.mClipAndScroll = Some(std::make_pair(scrollId, clipId));
- }
-
- clips.Apply(mBuilder);
- mItemClipStack.push_back(clips);
-
- SLH_LOG("done setup for %p\n", aItem);
-}
-
-std::pair<Maybe<wr::WrScrollId>, Maybe<wr::WrClipId>>
-ScrollingLayersHelper::DefineClipChain(nsDisplayItem* aItem,
- const ActiveScrolledRoot* aAsr,
- const DisplayItemClipChain* aChain,
- int32_t aAppUnitsPerDevPixel,
- const StackingContextHelper& aStackingContext)
-{
- // This is the main entry point for defining the clip chain for a display
- // item. This function recursively walks up the ASR chain and the display
- // item's clip chain to define all the ASRs and clips necessary. Each level
- // of the recursion defines one item, if it hasn't been defined already.
- // The |aAsr| and |aChain| parameters are the important ones to track during
- // the recursion; the rest of the parameters don't change.
- // At each level of the recursion, the return value is the pair of identifiers
- // that correspond to aAsr and aChain, respectively.
-
- // These are the possible cases when recursing:
- //
- // aAsr is null, aChain is null => base case; return
- // aAsr is non-null, aChain is null => recurse(aAsr->mParent, null),
- // then define aAsr
- // aAsr is null, aChain is non-null => assert(aChain->mASR == null),
- // recurse(null, aChain->mParent),
- // then define aChain
- // aChain->mASR == aAsr => recurse(aAsr, aChain->mParent),
- // then define aChain
- // aChain->mASR != aAsr => recurse(aAsr->mParent, aChain),
- // then define aAsr
- //
- // These can basically be collapsed down into two codepaths; one that recurses
- // on the ASR chain and one that recurses on the clip chain; that's what the
- // code below does.
-
- // in all of these cases, this invariant should hold:
- // PickDescendant(aChain->mASR, aAsr) == aAsr
- MOZ_ASSERT(!aChain || ActiveScrolledRoot::PickDescendant(aChain->mASR, aAsr) == aAsr);
-
- if (aChain && aChain->mASR == aAsr) {
- return RecurseAndDefineClip(aItem, aAsr, aChain, aAppUnitsPerDevPixel, aStackingContext);
- }
- if (aAsr) {
- return RecurseAndDefineAsr(aItem, aAsr, aChain, aAppUnitsPerDevPixel, aStackingContext);
- }
-
- MOZ_ASSERT(!aChain && !aAsr);
-
- return std::make_pair(Nothing(), Nothing());
-}
-
-std::pair<Maybe<wr::WrScrollId>, Maybe<wr::WrClipId>>
-ScrollingLayersHelper::RecurseAndDefineClip(nsDisplayItem* aItem,
- const ActiveScrolledRoot* aAsr,
- const DisplayItemClipChain* aChain,
- int32_t aAppUnitsPerDevPixel,
- const StackingContextHelper& aSc)
-{
- MOZ_ASSERT(aChain);
-
- // This will hold our return value
- std::pair<Maybe<wr::WrScrollId>, Maybe<wr::WrClipId>> ids;
-
- if (mBuilder->HasExtraClip()) {
- // We can't use the clip cache directly. However if there's an out-of-band clip that
- // was pushed on top of aChain, we should return the id for that OOB clip,
- // so that anything we want to define as a descendant of aChain we actually
- // end up defining as a descendant of the OOB clip.
- ids.second = mBuilder->GetCacheOverride(aChain);
- } else {
- const ClipIdMap& cache = mCacheStack.back();
- auto it = cache.find(aChain);
- if (it != cache.end()) {
- ids.second = Some(it->second);
- }
- }
- if (ids.second) {
- // If we've already got an id for this clip, we can early-exit
- if (aAsr) {
- ids.first = mBuilder->GetScrollIdForDefinedScrollLayer(aAsr->GetViewId());
- MOZ_ASSERT(ids.first);
- }
- return ids;
- }
-
- // If not, recurse to ensure all the ancestors are defined
- auto ancestorIds = DefineClipChain(
- aItem, aAsr, aChain->mParent, aAppUnitsPerDevPixel, aSc);
- ids = ancestorIds;
-
- if (!aChain->mClip.HasClip()) {
- // This item in the chain is a no-op, skip over it
- return ids;
- }
-
- // Now we need to figure out whether the new clip we're defining should be
- // a child of aChain->mParent, or of aAsr.
- if (aChain->mParent) {
- if (mBuilder->GetCacheOverride(aChain->mParent)) {
- // If the parent clip had an override (i.e. the parent display item pushed
- // an out-of-band clip), then we definitely want to use that as the parent
- // because everything defined inside that clip should have it as an
- // ancestor.
- ancestorIds.first = Nothing();
- } else if (aChain->mParent->mASR == aAsr) {
- // If the parent clip item shares the ASR, then this clip needs to be
- // a child of the aChain->mParent, which will already be a descendant of
- // the ASR.
- ancestorIds.first = Nothing();
- } else {
- // But if the ASRs are different, this is the outermost clip that's
- // still inside aAsr, and we need to make it a child of aAsr rather
- // than aChain->mParent.
- ancestorIds.second = Nothing();
- }
- } else {
- MOZ_ASSERT(!ancestorIds.second);
- FrameMetrics::ViewID viewId = aChain->mASR ? aChain->mASR->GetViewId() : FrameMetrics::NULL_SCROLL_ID;
-
- wr::WrScrollId rootId = wr::WrScrollId::RootScrollNode();
- auto scrollId = mBuilder->GetScrollIdForDefinedScrollLayer(viewId).valueOr(rootId);
- if (mBuilder->TopmostScrollId() == scrollId) {
- if (mBuilder->TopmostIsClip()) {
- // 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.
- ancestorIds.first = Nothing();
- ancestorIds.second = mBuilder->TopmostClipId();
- } else if (auto cs = EnclosingClipAndScroll()) {
- // If aChain->mASR is already the topmost scroll layer on the stack, but
- // it was pushed as part of a "clip and scroll" entry (i.e. because an
- // item had a clip scrolled by a different ASR than the item itself),
- // then we have need to propagate that behaviour as well. For example if
- // the enclosing display item pushed a ClipAndScroll with (scrollid=S,
- // clipid=C), then then clip we're defining here (call it D) needs to be
- // defined as a child of C, and we'll need to push the ClipAndScroll
- // (S, D) for this item. This hunk of code ensures that we define D
- // as a child of C, and when we set the needClipAndScroll flag elsewhere
- // in this file we make sure to set it for this scenario.
- MOZ_ASSERT(cs->first == scrollId);
- ancestorIds.first = Nothing();
- ancestorIds.second = cs->second;
- }
- }
- }
- // 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.
- MOZ_ASSERT(!(ancestorIds.first && ancestorIds.second));
-
- LayoutDeviceRect clip = LayoutDeviceRect::FromAppUnits(
- aChain->mClip.GetClipRect(), aAppUnitsPerDevPixel);
- nsTArray<wr::ComplexClipRegion> wrRoundedRects;
- aChain->mClip.ToComplexClipRegions(aAppUnitsPerDevPixel, aSc, wrRoundedRects);
-
- // Define the clip
- wr::WrClipId clipId = mBuilder->DefineClip(
- ancestorIds.first, ancestorIds.second,
- wr::ToRoundedLayoutRect(clip), &wrRoundedRects);
- if (!mBuilder->HasExtraClip()) {
- mCacheStack.back()[aChain] = clipId;
- }
-
- ids.second = Some(clipId);
- return ids;
-}
-
-std::pair<Maybe<wr::WrScrollId>, Maybe<wr::WrClipId>>
-ScrollingLayersHelper::RecurseAndDefineAsr(nsDisplayItem* aItem,
- const ActiveScrolledRoot* aAsr,
- const DisplayItemClipChain* aChain,
- int32_t aAppUnitsPerDevPixel,
- const StackingContextHelper& aSc)
-{
- MOZ_ASSERT(aAsr);
-
- // This will hold our return value
- std::pair<Maybe<wr::WrScrollId>, Maybe<wr::WrClipId>> ids;
-
- FrameMetrics::ViewID viewId = aAsr->GetViewId();
- if (auto scrollId = mBuilder->GetScrollIdForDefinedScrollLayer(viewId)) {
- // If we've already defined this scroll layer before, we can early-exit
- ids.first = scrollId;
- if (aChain) {
- if (mBuilder->HasExtraClip()) {
- ids.second = mBuilder->GetCacheOverride(aChain);
- } else {
- const ClipIdMap& cache = mCacheStack.back();
- auto it = cache.find(aChain);
- // If |it == cache.end()| here then we have run into a case where the
- // scroll layer was previously defined with a specific parent clip, and
- // now here it has a different parent clip. Gecko can create display
- // lists like this because it treats the ASR chain and clipping chain
- // more independently, but we can't yet represent this in WR. This is
- // tracked by bug 1409442. For now we'll just leave ids.second as
- // Nothing() which will effectively ignore the clip |aChain|. Once WR
- // supports multiple ancestors on a scroll layer we can deal with this
- // better. The layout/reftests/text/wordwrap-08.html has a Text display
- // item that exercises this case.
- if (it != cache.end()) {
- ids.second = Some(it->second);
- }
- }
- }
- return ids;
- }
-
- // If not, recurse to ensure all the ancestors are defined
- auto ancestorIds = DefineClipChain(
- aItem, aAsr->mParent, aChain, aAppUnitsPerDevPixel, aSc);
- ids = ancestorIds;
-
- Maybe<ScrollMetadata> metadata = aAsr->mScrollableFrame->ComputeScrollMetadata(
- mManager, aItem->ReferenceFrame(), ContainerLayerParameters(), nullptr);
- MOZ_ASSERT(metadata);
- FrameMetrics& metrics = metadata->GetMetrics();
-
- if (!metrics.IsScrollable()) {
- // This item in the chain is a no-op, skip over it
- return ids;
- }
-
- // Now we need to figure out whether the new clip we're defining should be
- // a child of aChain, or of aAsr->mParent, if we have both as a possibility.
- if (ancestorIds.first && ancestorIds.second) {
- MOZ_ASSERT(aAsr->mParent); // because ancestorIds.first
- MOZ_ASSERT(aChain); // because ancestorIds.second
- if (aChain->mASR && aChain->mASR == aAsr->mParent) {
- // aChain is scrolled by aAsr's parent, so we should use aChain as the
- // ancestor when defining the aAsr scroll layer.
- ancestorIds.first = Nothing();
- } else {
- // This scenario never seems to occur in practice, but if it did it would
- // mean that aChain is scrolled by one of aAsr's ancestors beyond the
- // parent, in which case we should use aAsr->mParent as the ancestor
- // when defining the aAsr scroll layer.
- ancestorIds.second = Nothing();
- }
- }
- // 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 scrollframe that we're
- // defining.
- MOZ_ASSERT(!(ancestorIds.first && ancestorIds.second));
-
- LayoutDeviceRect contentRect =
- metrics.GetExpandedScrollableRect() * metrics.GetDevPixelsPerCSSPixel();
- // TODO: check coordinate systems are sane here
- LayoutDeviceRect clipBounds =
- LayoutDeviceRect::FromUnknownRect(metrics.GetCompositionBounds().ToUnknownRect());
- // The content rect that we hand to PushScrollLayer should be relative to
- // the same origin as the clipBounds that we hand to PushScrollLayer - that
- // is, both of them should be relative to the stacking context `aSc`.
- // However, when we get the scrollable rect from the FrameMetrics, the origin
- // has nothing to do with the position of the frame but instead represents
- // the minimum allowed scroll offset of the scrollable content. While APZ
- // uses this to clamp the scroll position, we don't need to send this to
- // WebRender at all. Instead, we take the position from the composition
- // bounds.
- contentRect.MoveTo(clipBounds.TopLeft());
-
- auto scrollId = mBuilder->DefineScrollLayer(viewId,
- ancestorIds.first,
- ancestorIds.second,
- wr::ToRoundedLayoutRect(contentRect),
- wr::ToRoundedLayoutRect(clipBounds));
-
- ids.first = Some(scrollId);
- return ids;
-}
-
-const DisplayItemClipChain*
-ScrollingLayersHelper::ExtendChain(const DisplayItemClipChain* aClip)
-{
- // The intent of this function is to handle Gecko display list scenarios
- // like so:
- // nsDisplayFixedPosition with clip chain A -> B -> nullptr
- // nsDisplayBackgroundColor with clip chain B -> nullptr
- //
- // The specific types are not relevant, but the important part is that there
- // is a display item whose clip chain is a subchain of the enclosing display
- // item.
- //
- // The semantics of the gecko display items means that the two clip chains
- // should be intersected for the child display item; because one clip chain
- // is a subset of the other the intersection comes out to be clip chain from
- // the parent.
- // However, WebRender doesn't let us (yet) intersect clip chains, so one of
- // the jobs of ScrollingLayersHelper is to generate as-good-as-possible clip
- // chains by merging the necessary clips into a new clip chain. In the example
- // above, we really want the nsDisplayBackgroundColor to use the clip chain
- // from A rather than from B in order to get the right clips, and this
- // function "extends" an input of |B| and returns |A|.
-
- if (!aClip) {
- return aClip;
- }
- // mItemClipStack has the clips that we pushed for ancestor display items.
- size_t clipDepth = mItemClipStack.size();
- MOZ_ASSERT(clipDepth > 0);
- while (--clipDepth > 0) {
- const DisplayItemClipChain* enclosingClip = mItemClipStack[clipDepth - 1].mChain;
- if (!enclosingClip) {
- // This is a special case; if an item has a nullptr clipchain it basically
- // inherits the clipchain from its ancestor, so let's skip to that.
- continue;
- }
- if (aClip == enclosingClip) {
- // The ancestor clip chain is the same as our item's clip chain, so
- // we're done. Note that because this function will have run on the
- // ancestor as well, we can be assured via induction that there is no
- // ancestor beyond this one that has a longer superset-clipchain.
- return aClip;
- }
- const ClipIdMap& cache = mCacheStack.back();
- if (cache.find(enclosingClip) == cache.end()) {
- // The ancestor clip chain isn't in our clip cache, which means there
- // must be a reference frame between the ancestor item and this item.
- // Therefore we cannot use the enclosing clip, so let's abort
- return aClip;
- }
- for (const DisplayItemClipChain* i = enclosingClip->mParent; i; i = i->mParent) {
- if (i == aClip) {
- // aClip is contained inside the enclosingClip clipchain. Since the
- // enclosingClip also applies to the item we're currently processing,
- // we should use that as it is a better approximation to the real clip
- // set that applies to the item.
- SLH_LOG("extending clip %p to %p\n", aClip, enclosingClip);
- return enclosingClip;
- }
- }
- break;
- }
- return aClip;
-}
-
-Maybe<ScrollingLayersHelper::ClipAndScroll>
-ScrollingLayersHelper::EnclosingClipAndScroll() const
-{
- for (auto it = mItemClipStack.rbegin(); it != mItemClipStack.rend(); it++) {
- if (it->mClipAndScroll) {
- return it->mClipAndScroll;
- }
- // If an entry in the stack pushed a single clip or scroll without pushing
- // a mClipAndScroll, we abort because we are effectively no longer inside
- // a ClipAndScroll
- if (it->mClipId || it->mScrollId) {
- break;
- }
- }
- return Nothing();
-}
-
-ScrollingLayersHelper::~ScrollingLayersHelper()
-{
- MOZ_ASSERT(!mBuilder);
- MOZ_ASSERT(mCacheStack.empty());
- MOZ_ASSERT(mItemClipStack.empty());
-}
-
-ScrollingLayersHelper::ItemClips::ItemClips(const ActiveScrolledRoot* aAsr,
- const DisplayItemClipChain* aChain)
- : mAsr(aAsr)
- , mChain(aChain)
-{
-}
-
-void
-ScrollingLayersHelper::ItemClips::Apply(wr::DisplayListBuilder* aBuilder)
-{
- if (mScrollId) {
- aBuilder->PushScrollLayer(mScrollId.ref());
- }
- if (mClipId) {
- aBuilder->PushClip(mClipId.ref());
- }
- if (mClipAndScroll) {
- aBuilder->PushClipAndScrollInfo(mClipAndScroll->first,
- mClipAndScroll->second.ptrOr(nullptr));
- }
-}
-
-void
-ScrollingLayersHelper::ItemClips::Unapply(wr::DisplayListBuilder* aBuilder)
-{
- if (mClipAndScroll) {
- aBuilder->PopClipAndScrollInfo();
- }
- if (mClipId) {
- aBuilder->PopClip();
- }
- if (mScrollId) {
- aBuilder->PopScrollLayer();
- }
-}
-
-bool
-ScrollingLayersHelper::ItemClips::HasSameInputs(const ItemClips& aOther)
-{
- return mAsr == aOther.mAsr &&
- mChain == aOther.mChain;
-}
-
-} // namespace layers
-} // namespace mozilla
deleted file mode 100644
--- a/gfx/layers/wr/ScrollingLayersHelper.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_SCROLLINGLAYERSHELPER_H
-#define GFX_SCROLLINGLAYERSHELPER_H
-
-#include <unordered_map>
-
-#include "mozilla/Attributes.h"
-#include "mozilla/webrender/WebRenderAPI.h"
-#include "FrameMetrics.h"
-
-class nsDisplayItem;
-
-namespace mozilla {
-
-struct ActiveScrolledRoot;
-struct DisplayItemClipChain;
-
-namespace wr {
-class DisplayListBuilder;
-}
-
-namespace layers {
-
-struct FrameMetrics;
-class StackingContextHelper;
-class WebRenderLayerManager;
-
-class ScrollingLayersHelper
-{
-public:
- ScrollingLayersHelper();
-
- void BeginBuild(WebRenderLayerManager* aManager,
- wr::DisplayListBuilder& aBuilder);
- void EndBuild();
-
- void BeginList(const StackingContextHelper& aStackingContext);
- void EndList(const StackingContextHelper& aStackingContext);
-
- void BeginItem(nsDisplayItem* aItem,
- const StackingContextHelper& aStackingContext);
- ~ScrollingLayersHelper();
-
-private:
- typedef std::pair<wr::WrScrollId, Maybe<wr::WrClipId>> ClipAndScroll;
-
- std::pair<Maybe<wr::WrScrollId>, Maybe<wr::WrClipId>>
- DefineClipChain(nsDisplayItem* aItem,
- const ActiveScrolledRoot* aAsr,
- const DisplayItemClipChain* aChain,
- int32_t aAppUnitsPerDevPixel,
- const StackingContextHelper& aStackingContext);
-
- std::pair<Maybe<wr::WrScrollId>, Maybe<wr::WrClipId>>
- RecurseAndDefineClip(nsDisplayItem* aItem,
- const ActiveScrolledRoot* aAsr,
- const DisplayItemClipChain* aChain,
- int32_t aAppUnitsPerDevPixel,
- const StackingContextHelper& aSc);
-
- std::pair<Maybe<wr::WrScrollId>, Maybe<wr::WrClipId>>
- RecurseAndDefineAsr(nsDisplayItem* aItem,
- const ActiveScrolledRoot* aAsr,
- const DisplayItemClipChain* aChain,
- int32_t aAppUnitsPerDevPixel,
- const StackingContextHelper& aSc);
-
- const DisplayItemClipChain* ExtendChain(const DisplayItemClipChain* aClip);
- Maybe<ClipAndScroll> EnclosingClipAndScroll() const;
-
- typedef std::unordered_map<const DisplayItemClipChain*, wr::WrClipId> ClipIdMap;
-
- WebRenderLayerManager* MOZ_NON_OWNING_REF mManager;
- wr::DisplayListBuilder* mBuilder;
- // Stack of clip caches. There is one entry in the stack for each reference
- // frame that is currently pushed in WR (a reference frame is a stacking
- // context with a non-identity transform). Each entry contains a map that
- // maps gecko DisplayItemClipChain objects to webrender WrClipIds, which
- // allows us to avoid redefining identical clips in WR. We need to keep a
- // separate cache per reference frame because the DisplayItemClipChain items
- // themselves get deduplicated without regard to reference frames, but on the
- // WR side we need to create different clips if they are in different
- // reference frames.
- std::vector<ClipIdMap> mCacheStack;
-
- struct ItemClips {
- ItemClips(const ActiveScrolledRoot* aAsr,
- const DisplayItemClipChain* aChain);
-
- const ActiveScrolledRoot* mAsr;
- const DisplayItemClipChain* mChain;
-
- Maybe<wr::WrScrollId> mScrollId;
- Maybe<wr::WrClipId> mClipId;
- Maybe<ClipAndScroll> mClipAndScroll;
-
- void Apply(wr::DisplayListBuilder* aBuilder);
- void Unapply(wr::DisplayListBuilder* aBuilder);
- bool HasSameInputs(const ItemClips& aOther);
- };
-
- std::vector<ItemClips> mItemClipStack;
-};
-
-} // namespace layers
-} // namespace mozilla
-
-#endif
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -69,17 +69,18 @@ StackingContextHelper::StackingContextHe
aPerspectivePtr,
wr::ToMixBlendMode(aMixBlendMode),
aFilters,
aBackfaceVisible,
rasterSpace);
mAffectsClipPositioning =
(aTransformPtr && !aTransformPtr->IsIdentity()) ||
- (aBounds.TopLeft() != LayoutDevicePoint());
+ (aBounds.TopLeft() != LayoutDevicePoint()) ||
+ (aAnimation && aAnimation->effect_type == wr::WrAnimationType::Transform);
}
StackingContextHelper::~StackingContextHelper()
{
if (mBuilder) {
mBuilder->PopStackingContext();
}
}
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -5,21 +5,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebRenderCommandBuilder.h"
#include "BasicLayers.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Types.h"
+#include "mozilla/layers/ClipManager.h"
#include "mozilla/layers/ImageClient.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h"
-#include "mozilla/layers/ScrollingLayersHelper.h"
#include "mozilla/layers/SharedSurfacesChild.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/UpdateImageHelper.h"
#include "mozilla/layers/WebRenderDrawEventRecorder.h"
#include "UnitTransforms.h"
#include "gfxEnv.h"
#include "nsDisplayListInvalidation.h"
@@ -198,24 +198,24 @@ TakeExternalSurfaces(WebRenderDrawEventR
auto sharedSurface = static_cast<SourceSurfaceSharedData*>(surface.get());
SharedSurfacesChild::Share(sharedSurface, aManager, aResources, key);
}
}
struct DIGroup;
struct Grouper
{
- explicit Grouper(ScrollingLayersHelper& aScrollingHelper)
- : mScrollingHelper(aScrollingHelper)
+ explicit Grouper(ClipManager& aClipManager)
+ : mClipManager(aClipManager)
{}
int32_t mAppUnitsPerDevPixel;
std::vector<nsDisplayItem*> mItemStack;
nsDisplayListBuilder* mDisplayListBuilder;
- ScrollingLayersHelper& mScrollingHelper;
+ ClipManager& mClipManager;
Matrix mTransform;
// Paint the list of aChildren display items.
void PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem, const IntRect& aItemBounds,
nsDisplayList* aChildren, gfxContext* aContext,
WebRenderDrawEventRecorder* aRecorder);
// Builds groups of display items split based on 'layer activity'
@@ -911,17 +911,17 @@ Grouper::ConstructGroups(WebRenderComman
DIGroup* currentGroup = aGroup;
nsDisplayItem* item = aList->GetBottom();
nsDisplayItem* startOfCurrentGroup = item;
while (item) {
nsDisplayList* children = item->GetChildren();
if (IsItemProbablyActive(item, mDisplayListBuilder)) {
currentGroup->EndGroup(aCommandBuilder->mManager, aBuilder, aResources, this, startOfCurrentGroup, item);
- mScrollingHelper.BeginItem(item, aSc);
+ mClipManager.BeginItem(item, aSc);
sIndent++;
// Note: this call to CreateWebRenderCommands can recurse back into
// this function.
bool createdWRCommands =
item->CreateWebRenderCommands(aBuilder, aResources, aSc, aCommandBuilder->mManager,
mDisplayListBuilder);
sIndent--;
MOZ_RELEASE_ASSERT(createdWRCommands, "active transforms should always succeed at creating WebRender commands");
@@ -1044,18 +1044,18 @@ WebRenderCommandBuilder::DoGroupingForDi
const StackingContextHelper& aSc,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources)
{
if (!aList->GetBottom()) {
return;
}
- mScrollingHelper.BeginList(aSc);
- Grouper g(mScrollingHelper);
+ mClipManager.BeginList(aSc);
+ Grouper g(mClipManager);
int32_t appUnitsPerDevPixel = aWrappingItem->Frame()->PresContext()->AppUnitsPerDevPixel();
GP("DoGroupingForDisplayList\n");
g.mDisplayListBuilder = aDisplayListBuilder;
RefPtr<WebRenderGroupData> groupData = CreateOrRecycleWebRenderUserData<WebRenderGroupData>(aWrappingItem);
bool snapped;
nsRect groupBounds = aWrappingItem->GetBounds(aDisplayListBuilder, &snapped);
DIGroup& group = groupData->mSubGroup;
@@ -1087,17 +1087,17 @@ WebRenderCommandBuilder::DoGroupingForDi
g.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
g.mTransform = Matrix::Scaling(scale.width, scale.height);
group.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
group.mGroupBounds = groupBounds;
group.mScale = scale;
group.mLayerBounds = LayerIntRect::FromUnknownRect(group.mGroupBounds.ScaleToOutsidePixels(scale.width, scale.height, group.mAppUnitsPerDevPixel));
group.mAnimatedGeometryRootOrigin = group.mGroupBounds.TopLeft();
g.ConstructGroups(this, aBuilder, aResources, &group, aList, aSc);
- mScrollingHelper.EndList(aSc);
+ mClipManager.EndList(aSc);
}
void
WebRenderCommandBuilder::Destroy()
{
mLastCanvasDatas.Clear();
ClearCachedResources();
}
@@ -1130,17 +1130,17 @@ WebRenderCommandBuilder::BuildWebRenderC
wr::LayoutSize& aContentSize,
const nsTArray<wr::WrFilterOp>& aFilters)
{
StackingContextHelper sc;
aScrollData = WebRenderScrollData(mManager);
MOZ_ASSERT(mLayerScrollData.empty());
mLastCanvasDatas.Clear();
mLastAsr = nullptr;
- mScrollingHelper.BeginBuild(mManager, aBuilder);
+ mClipManager.BeginBuild(mManager, aBuilder);
{
StackingContextHelper pageRootSc(sc, aBuilder, aFilters);
CreateWebRenderCommandsFromDisplayList(aDisplayList, nullptr, aDisplayListBuilder,
pageRootSc, aBuilder, aResourceUpdates);
}
// Make a "root" layer data that has everything else as descendants
@@ -1155,17 +1155,17 @@ WebRenderCommandBuilder::BuildWebRenderC
}
// Append the WebRenderLayerScrollData items into WebRenderScrollData
// in reverse order, from topmost to bottommost. This is in keeping with
// the semantics of WebRenderScrollData.
for (auto i = mLayerScrollData.crbegin(); i != mLayerScrollData.crend(); i++) {
aScrollData.AddLayerData(*i);
}
mLayerScrollData.clear();
- mScrollingHelper.EndBuild();
+ mClipManager.EndBuild();
// Remove the user data those are not displayed on the screen and
// also reset the data to unused for next transaction.
RemoveUnusedAndResetWebRenderUserData();
}
void
WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDisplayList,
@@ -1177,17 +1177,17 @@ WebRenderCommandBuilder::CreateWebRender
{
if (mDoGrouping) {
MOZ_RELEASE_ASSERT(aWrappingItem, "Only the root list should have a null wrapping item, and mDoGrouping should never be true for the root list.");
GP("actually entering the grouping code\n");
DoGroupingForDisplayList(aDisplayList, aWrappingItem, aDisplayListBuilder, aSc, aBuilder, aResources);
return;
}
- mScrollingHelper.BeginList(aSc);
+ mClipManager.BeginList(aSc);
bool apzEnabled = mManager->AsyncPanZoomEnabled();
EventRegions eventRegions;
FlattenedDisplayItemIterator iter(aDisplayListBuilder, aDisplayList);
while (nsDisplayItem* i = iter.GetNext()) {
nsDisplayItem* item = i;
DisplayItemType itemType = item->GetType();
@@ -1282,17 +1282,17 @@ WebRenderCommandBuilder::CreateWebRender
// If we're going to create a new layer data for this item, stash the
// ASR so that if we recurse into a sublist they will know where to stop
// walking up their ASR chain when building scroll metadata.
if (forceNewLayerData) {
mAsrStack.push_back(asr);
}
}
- mScrollingHelper.BeginItem(item, aSc);
+ mClipManager.BeginItem(item, aSc);
if (itemType != DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
AutoRestore<bool> restoreDoGrouping(mDoGrouping);
if (itemType == DisplayItemType::TYPE_SVG_WRAPPER) {
// Inside an <svg>, all display items that are not LAYER_ACTIVE wrapper
// display items (like animated transforms / opacity) share the same
// animated geometry root, so we can combine subsequent items of that
// type into the same image.
@@ -1347,17 +1347,30 @@ WebRenderCommandBuilder::CreateWebRender
// the most recently created layer data will have been created by an item
// with matching ASRs.
if (!eventRegions.IsEmpty()) {
MOZ_ASSERT(apzEnabled);
MOZ_ASSERT(!mLayerScrollData.empty());
mLayerScrollData.back().AddEventRegions(eventRegions);
}
- mScrollingHelper.EndList(aSc);
+ mClipManager.EndList(aSc);
+}
+
+void
+WebRenderCommandBuilder::PushOverrideForASR(const ActiveScrolledRoot* aASR,
+ const Maybe<wr::WrClipId>& aClipId)
+{
+ mClipManager.PushOverrideForASR(aASR, aClipId);
+}
+
+void
+WebRenderCommandBuilder::PopOverrideForASR(const ActiveScrolledRoot* aASR)
+{
+ mClipManager.PopOverrideForASR(aASR);
}
Maybe<wr::ImageKey>
WebRenderCommandBuilder::CreateImageKey(nsDisplayItem* aItem,
ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -3,17 +3,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFX_WEBRENDERCOMMANDBUILDER_H
#define GFX_WEBRENDERCOMMANDBUILDER_H
#include "mozilla/webrender/WebRenderAPI.h"
-#include "mozilla/layers/ScrollingLayersHelper.h"
+#include "mozilla/layers/ClipManager.h"
#include "mozilla/layers/WebRenderMessages.h"
#include "mozilla/layers/WebRenderScrollData.h"
#include "mozilla/layers/WebRenderUserData.h"
#include "nsDisplayList.h"
#include "nsIFrame.h"
namespace mozilla {
@@ -50,16 +50,20 @@ public:
void BuildWebRenderCommands(wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResourceUpdates,
nsDisplayList* aDisplayList,
nsDisplayListBuilder* aDisplayListBuilder,
WebRenderScrollData& aScrollData,
wr::LayoutSize& aContentSize,
const nsTArray<wr::WrFilterOp>& aFilters);
+ void PushOverrideForASR(const ActiveScrolledRoot* aASR,
+ const Maybe<wr::WrClipId>& aClipId);
+ void PopOverrideForASR(const ActiveScrolledRoot* aASR);
+
Maybe<wr::ImageKey> CreateImageKey(nsDisplayItem* aItem,
ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
gfx::IntSize& aSize,
const Maybe<LayoutDeviceRect>& aAsyncImageBounds);
@@ -154,18 +158,19 @@ public:
if (T::Type() == WebRenderUserData::UserDataType::eCanvas) {
mLastCanvasDatas.PutEntry(data->AsCanvasData());
}
RefPtr<T> res = static_cast<T*>(data.get());
return res.forget();
}
WebRenderLayerManager* mManager;
+
private:
- ScrollingLayersHelper mScrollingHelper;
+ ClipManager mClipManager;
// We use this as a temporary data structure while building the mScrollData
// inside a layers-free transaction.
std::vector<WebRenderLayerScrollData> mLayerScrollData;
// We use this as a temporary data structure to track the current display
// item's ASR as we recurse in CreateWebRenderCommandsFromDisplayList. We
// need this so that WebRenderLayerScrollData items that deeper in the
// tree don't duplicate scroll metadata that their ancestors already have.
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -1,17 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebRenderAPI.h"
-#include "DisplayItemClipChain.h"
#include "gfxPrefs.h"
#include "LayersLogging.h"
#include "mozilla/webrender/RendererOGL.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/webrender/RenderCompositor.h"
#include "mozilla/widget/CompositorWidget.h"
#include "mozilla/layers/SynchronousTask.h"
@@ -800,122 +799,69 @@ DisplayListBuilder::PushStackingContext(
void
DisplayListBuilder::PopStackingContext()
{
WRDL_LOG("PopStackingContext\n", mWrState);
wr_dp_pop_stacking_context(mWrState);
}
+wr::WrClipChainId
+DisplayListBuilder::DefineClipChain(const Maybe<wr::WrClipChainId>& aParent,
+ const nsTArray<wr::WrClipId>& aClips)
+{
+ nsTArray<size_t> clipIds;
+ for (wr::WrClipId id : aClips) {
+ clipIds.AppendElement(id.id);
+ }
+ uint64_t clipchainId = wr_dp_define_clipchain(mWrState,
+ aParent ? &(aParent->id) : nullptr,
+ clipIds.Elements(), clipIds.Length());
+ WRDL_LOG("DefineClipChain id=%" PRIu64 " p=%s clips=%zu\n", mWrState,
+ clipchainId,
+ aParent ? Stringify(aParent->id).c_str() : "(nil)",
+ clipIds.Length());
+ return wr::WrClipChainId{ clipchainId };
+}
+
wr::WrClipId
-DisplayListBuilder::DefineClip(const Maybe<wr::WrScrollId>& aAncestorScrollId,
- const Maybe<wr::WrClipId>& aAncestorClipId,
+DisplayListBuilder::DefineClip(const Maybe<wr::WrClipId>& aParentId,
const wr::LayoutRect& aClipRect,
const nsTArray<wr::ComplexClipRegion>* aComplex,
const wr::WrImageMask* aMask)
{
- const size_t* parentId = nullptr;
- if (aAncestorScrollId) {
- parentId = &(aAncestorScrollId.ref().id);
- } else if (aAncestorClipId) {
- parentId = &(aAncestorClipId.ref().id);
- }
size_t clip_id = wr_dp_define_clip(mWrState,
- parentId,
+ aParentId ? &(aParentId->id) : nullptr,
aClipRect,
aComplex ? aComplex->Elements() : nullptr,
aComplex ? aComplex->Length() : 0,
aMask);
- WRDL_LOG("DefineClip id=%zu as=%s ac=%s r=%s m=%p b=%s complex=%zu\n", mWrState,
- clip_id,
- aAncestorScrollId ? Stringify(aAncestorScrollId.ref().id).c_str() : "(nil)",
- aAncestorClipId ? Stringify(aAncestorClipId.ref().id).c_str() : "(nil)",
+ WRDL_LOG("DefineClip id=%zu p=%s r=%s m=%p b=%s complex=%zu\n", mWrState,
+ clip_id, aParentId ? Stringify(aParentId->id).c_str() : "(nil)",
Stringify(aClipRect).c_str(), aMask,
aMask ? Stringify(aMask->rect).c_str() : "none",
aComplex ? aComplex->Length() : 0);
return wr::WrClipId { clip_id };
}
void
-DisplayListBuilder::PushClip(const wr::WrClipId& aClipId,
- const DisplayItemClipChain* aParent)
+DisplayListBuilder::PushClip(const wr::WrClipId& aClipId)
{
- wr_dp_push_clip(mWrState, aClipId.id);
WRDL_LOG("PushClip id=%zu\n", mWrState, aClipId.id);
- if (!aParent) {
- mClipStack.push_back(wr::ScrollOrClipId(aClipId));
- } else {
- PushCacheOverride(aParent, aClipId);
- }
-}
-
-void
-DisplayListBuilder::PopClip(const DisplayItemClipChain* aParent)
-{
- WRDL_LOG("PopClip\n", mWrState);
- if (!aParent) {
- MOZ_ASSERT(mClipStack.back().is<wr::WrClipId>());
- mClipStack.pop_back();
- } else {
- PopCacheOverride(aParent);
- }
- wr_dp_pop_clip(mWrState);
+ wr_dp_push_clip(mWrState, aClipId.id);
}
void
-DisplayListBuilder::PushCacheOverride(const DisplayItemClipChain* aParent,
- const wr::WrClipId& aClipId)
+DisplayListBuilder::PopClip()
{
- // We need to walk the entire clip chain from aParent up and install aClipId
- // as an override for all of them. This is so that nested display items end up
- // with the correct parent clip regardless of which outside clip their clip
- // chains are attached to. Example:
- // nsDisplayStickyPosition with clipChain D -> C -> B -> A -> nullptr
- // nsDisplayItem with clipChain F -> E -> B -> A -> nullptr
- // In this case the sticky clip that is generated by the sticky display item
- // is defined as a child of D, which is a child of C and so on. When we go
- // to define E for the nested display item, we want to make sure that it
- // is defined as a child of sticky clip, regardless of which of {D, C, B, A}
- // it has as a parent. {D, C, B, A} are what I refer to as the "outside clips"
- // because they are "outside" the sticky clip, and if we define E as a child
- // of any of those clips directly, then we end up losing the sticky clip from
- // the WR clip chain of the nested item. This is why we install cache
- // overrides for all of them so that when we walk the nested item's clip chain
- // from E to B we discover that really we want to use the sticky clip as E's
- // parent.
- for (const DisplayItemClipChain* i = aParent; i; i = i->mParent) {
- auto it = mCacheOverride.insert({ i, std::vector<wr::WrClipId>() });
- it.first->second.push_back(aClipId);
- WRDL_LOG("Pushing override %p -> %zu\n", mWrState, i, aClipId.id);
- }
+ WRDL_LOG("PopClip\n", mWrState);
+ wr_dp_pop_clip(mWrState);
}
-void
-DisplayListBuilder::PopCacheOverride(const DisplayItemClipChain* aParent)
-{
- for (const DisplayItemClipChain* i = aParent; i; i = i->mParent) {
- auto it = mCacheOverride.find(i);
- MOZ_ASSERT(it != mCacheOverride.end());
- MOZ_ASSERT(!(it->second.empty()));
- WRDL_LOG("Popping override %p -> %zu\n", mWrState, i, it->second.back().id);
- it->second.pop_back();
- if (it->second.empty()) {
- mCacheOverride.erase(it);
- }
- }
-}
-
-Maybe<wr::WrClipId>
-DisplayListBuilder::GetCacheOverride(const DisplayItemClipChain* aParent)
-{
- auto it = mCacheOverride.find(aParent);
- return it == mCacheOverride.end() ? Nothing() : Some(it->second.back());
-}
-
-wr::WrStickyId
+wr::WrClipId
DisplayListBuilder::DefineStickyFrame(const wr::LayoutRect& aContentRect,
const float* aTopMargin,
const float* aRightMargin,
const float* aBottomMargin,
const float* aLeftMargin,
const StickyOffsetBounds& aVerticalBounds,
const StickyOffsetBounds& aHorizontalBounds,
const wr::LayoutVector2D& aAppliedOffset)
@@ -928,127 +874,77 @@ DisplayListBuilder::DefineStickyFrame(co
Stringify(aContentRect).c_str(),
aTopMargin ? Stringify(*aTopMargin).c_str() : "none",
aRightMargin ? Stringify(*aRightMargin).c_str() : "none",
aBottomMargin ? Stringify(*aBottomMargin).c_str() : "none",
aLeftMargin ? Stringify(*aLeftMargin).c_str() : "none",
Stringify(aVerticalBounds).c_str(),
Stringify(aHorizontalBounds).c_str(),
Stringify(aAppliedOffset).c_str());
- return wr::WrStickyId { id };
+ return wr::WrClipId { id };
}
-void
-DisplayListBuilder::PushStickyFrame(const wr::WrStickyId& aStickyId,
- const DisplayItemClipChain* aParent)
-{
- wr_dp_push_clip(mWrState, aStickyId.id);
- WRDL_LOG("PushSticky id=%zu\n", mWrState, aStickyId.id);
- // inside WR, a sticky id is just a regular clip id. so we can do some
- // handwaving here and turn the WrStickyId into a WrclipId and treat it
- // like any other out-of-band clip.
- wr::WrClipId stickyIdAsClipId;
- stickyIdAsClipId.id = aStickyId.id;
- PushCacheOverride(aParent, stickyIdAsClipId);
-}
-
-void
-DisplayListBuilder::PopStickyFrame(const DisplayItemClipChain* aParent)
-{
- WRDL_LOG("PopSticky\n", mWrState);
- PopCacheOverride(aParent);
- wr_dp_pop_clip(mWrState);
-}
-
-Maybe<wr::WrScrollId>
+Maybe<wr::WrClipId>
DisplayListBuilder::GetScrollIdForDefinedScrollLayer(layers::FrameMetrics::ViewID aViewId) const
{
if (aViewId == layers::FrameMetrics::NULL_SCROLL_ID) {
- return Some(wr::WrScrollId::RootScrollNode());
+ return Some(wr::WrClipId::RootScrollNode());
}
auto it = mScrollIds.find(aViewId);
if (it == mScrollIds.end()) {
return Nothing();
}
return Some(it->second);
}
-wr::WrScrollId
+wr::WrClipId
DisplayListBuilder::DefineScrollLayer(const layers::FrameMetrics::ViewID& aViewId,
- const Maybe<wr::WrScrollId>& aAncestorScrollId,
- const Maybe<wr::WrClipId>& aAncestorClipId,
+ const Maybe<wr::WrClipId>& aParentId,
const wr::LayoutRect& aContentRect,
const wr::LayoutRect& aClipRect)
{
- const size_t* parentId = nullptr;
- if (aAncestorScrollId) {
- parentId = &(aAncestorScrollId.ref().id);
- } else if (aAncestorClipId) {
- parentId = &(aAncestorClipId.ref().id);
- }
- WRDL_LOG("DefineScrollLayer id=%" PRIu64 " as=%s ac=%s co=%s cl=%s\n", mWrState,
- aViewId,
- aAncestorScrollId ? Stringify(aAncestorScrollId.ref().id).c_str() : "(nil)",
- aAncestorClipId ? Stringify(aAncestorClipId.ref().id).c_str() : "(nil)",
- Stringify(aContentRect).c_str(), Stringify(aClipRect).c_str());
-
auto it = mScrollIds.find(aViewId);
if (it != mScrollIds.end()) {
return it->second;
}
// We haven't defined aViewId before, so let's define it now.
size_t numericScrollId = wr_dp_define_scroll_layer(
mWrState,
aViewId,
- parentId,
+ aParentId ? &(aParentId->id) : nullptr,
aContentRect,
aClipRect);
- auto wrScrollId = wr::WrScrollId { numericScrollId };
- mScrollIds[aViewId] = wrScrollId;
- return wrScrollId;
-}
-void
-DisplayListBuilder::PushScrollLayer(const wr::WrScrollId& aScrollId)
-{
- WRDL_LOG("PushScrollLayer id=%zu\n", mWrState, aScrollId.id);
- wr_dp_push_scroll_layer(mWrState, aScrollId.id);
- mClipStack.push_back(wr::ScrollOrClipId(aScrollId));
+ WRDL_LOG("DefineScrollLayer id=%" PRIu64 "/%zu p=%s co=%s cl=%s\n", mWrState,
+ aViewId, numericScrollId,
+ aParentId ? Stringify(aParentId->id).c_str() : "(nil)",
+ Stringify(aContentRect).c_str(), Stringify(aClipRect).c_str());
+
+ auto clipId = wr::WrClipId { numericScrollId };
+ mScrollIds[aViewId] = clipId;
+ return clipId;
}
void
-DisplayListBuilder::PopScrollLayer()
-{
- MOZ_ASSERT(mClipStack.back().is<wr::WrScrollId>());
- WRDL_LOG("PopScrollLayer id=%zu\n", mWrState,
- mClipStack.back().as<wr::WrScrollId>().id);
- mClipStack.pop_back();
- wr_dp_pop_scroll_layer(mWrState);
-}
-
-void
-DisplayListBuilder::PushClipAndScrollInfo(const wr::WrScrollId& aScrollId,
- const wr::WrClipId* aClipId)
+DisplayListBuilder::PushClipAndScrollInfo(const wr::WrClipId& aScrollId,
+ const wr::WrClipChainId* aClipChainId)
{
WRDL_LOG("PushClipAndScroll s=%zu c=%s\n", mWrState, aScrollId.id,
- aClipId ? Stringify(aClipId->id).c_str() : "none");
+ aClipChainId ? Stringify(aClipChainId->id).c_str() : "none");
wr_dp_push_clip_and_scroll_info(mWrState, aScrollId.id,
- aClipId ? &(aClipId->id) : nullptr);
- mClipStack.push_back(wr::ScrollOrClipId(aScrollId));
+ aClipChainId ? &(aClipChainId->id) : nullptr);
}
void
DisplayListBuilder::PopClipAndScrollInfo()
{
- MOZ_ASSERT(mClipStack.back().is<wr::WrScrollId>());
WRDL_LOG("PopClipAndScroll\n", mWrState);
- mClipStack.pop_back();
wr_dp_pop_clip_and_scroll_info(mWrState);
}
void
DisplayListBuilder::PushRect(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
const wr::ColorF& aColor)
@@ -1322,47 +1218,16 @@ DisplayListBuilder::PushBoxShadow(const
const wr::BoxShadowClipMode& aClipMode)
{
wr_dp_push_box_shadow(mWrState, aRect, aClip, aIsBackfaceVisible,
aBoxBounds, aOffset, aColor,
aBlurRadius, aSpreadRadius, aBorderRadius,
aClipMode);
}
-Maybe<wr::WrClipId>
-DisplayListBuilder::TopmostClipId()
-{
- for (auto it = mClipStack.crbegin(); it != mClipStack.crend(); it++) {
- if (it->is<wr::WrClipId>()) {
- return Some(it->as<wr::WrClipId>());
- }
- }
- return Nothing();
-}
-
-wr::WrScrollId
-DisplayListBuilder::TopmostScrollId()
-{
- for (auto it = mClipStack.crbegin(); it != mClipStack.crend(); it++) {
- if (it->is<wr::WrScrollId>()) {
- return it->as<wr::WrScrollId>();
- }
- }
- return wr::WrScrollId::RootScrollNode();
-}
-
-bool
-DisplayListBuilder::TopmostIsClip()
-{
- if (mClipStack.empty()) {
- return false;
- }
- return mClipStack.back().is<wr::WrClipId>();
-}
-
void
DisplayListBuilder::SetHitTestInfo(const layers::FrameMetrics::ViewID& aScrollId,
gfx::CompositorHitTestInfo aHitInfo)
{
static_assert(sizeof(gfx::CompositorHitTestInfo) == sizeof(uint16_t),
"CompositorHitTestInfo should be u16-sized");
wr_set_item_tag(mWrState, aScrollId, static_cast<uint16_t>(aHitInfo));
}
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -18,18 +18,16 @@
#include "mozilla/webrender/webrender_ffi.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "FrameMetrics.h"
#include "GLTypes.h"
#include "Units.h"
namespace mozilla {
-struct DisplayItemClipChain;
-
namespace widget {
class CompositorWidget;
}
namespace layers {
class CompositorBridgeParent;
class WebRenderBridgeParent;
}
@@ -289,48 +287,43 @@ public:
wr::TransformStyle aTransformStyle,
const gfx::Matrix4x4* aPerspective,
const wr::MixBlendMode& aMixBlendMode,
const nsTArray<wr::WrFilterOp>& aFilters,
bool aIsBackfaceVisible,
const wr::GlyphRasterSpace& aRasterSpace);
void PopStackingContext();
- wr::WrClipId DefineClip(const Maybe<wr::WrScrollId>& aAncestorScrollId,
- const Maybe<wr::WrClipId>& aAncestorClipId,
+ wr::WrClipChainId DefineClipChain(const Maybe<wr::WrClipChainId>& aParent,
+ const nsTArray<wr::WrClipId>& aClips);
+
+ wr::WrClipId DefineClip(const Maybe<wr::WrClipId>& aParentId,
const wr::LayoutRect& aClipRect,
const nsTArray<wr::ComplexClipRegion>* aComplex = nullptr,
const wr::WrImageMask* aMask = nullptr);
- void PushClip(const wr::WrClipId& aClipId, const DisplayItemClipChain* aParent = nullptr);
- void PopClip(const DisplayItemClipChain* aParent = nullptr);
- Maybe<wr::WrClipId> GetCacheOverride(const DisplayItemClipChain* aParent);
+ void PushClip(const wr::WrClipId& aClipId);
+ void PopClip();
- wr::WrStickyId DefineStickyFrame(const wr::LayoutRect& aContentRect,
- const float* aTopMargin,
- const float* aRightMargin,
- const float* aBottomMargin,
- const float* aLeftMargin,
- const StickyOffsetBounds& aVerticalBounds,
- const StickyOffsetBounds& aHorizontalBounds,
- const wr::LayoutVector2D& aAppliedOffset);
- void PushStickyFrame(const wr::WrStickyId& aStickyId,
- const DisplayItemClipChain* aParent);
- void PopStickyFrame(const DisplayItemClipChain* aParent);
+ wr::WrClipId DefineStickyFrame(const wr::LayoutRect& aContentRect,
+ const float* aTopMargin,
+ const float* aRightMargin,
+ const float* aBottomMargin,
+ const float* aLeftMargin,
+ const StickyOffsetBounds& aVerticalBounds,
+ const StickyOffsetBounds& aHorizontalBounds,
+ const wr::LayoutVector2D& aAppliedOffset);
- Maybe<wr::WrScrollId> GetScrollIdForDefinedScrollLayer(layers::FrameMetrics::ViewID aViewId) const;
- wr::WrScrollId DefineScrollLayer(const layers::FrameMetrics::ViewID& aViewId,
- const Maybe<wr::WrScrollId>& aAncestorScrollId,
- const Maybe<wr::WrClipId>& aAncestorClipId,
- const wr::LayoutRect& aContentRect, // TODO: We should work with strongly typed rects
- const wr::LayoutRect& aClipRect);
- void PushScrollLayer(const wr::WrScrollId& aScrollId);
- void PopScrollLayer();
+ Maybe<wr::WrClipId> GetScrollIdForDefinedScrollLayer(layers::FrameMetrics::ViewID aViewId) const;
+ wr::WrClipId DefineScrollLayer(const layers::FrameMetrics::ViewID& aViewId,
+ const Maybe<wr::WrClipId>& aParentId,
+ const wr::LayoutRect& aContentRect, // TODO: We should work with strongly typed rects
+ const wr::LayoutRect& aClipRect);
- void PushClipAndScrollInfo(const wr::WrScrollId& aScrollId,
- const wr::WrClipId* aClipId);
+ void PushClipAndScrollInfo(const wr::WrClipId& aScrollId,
+ const wr::WrClipChainId* aClipChainId);
void PopClipAndScrollInfo();
void PushRect(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
const wr::ColorF& aColor);
void PushClearRect(const wr::LayoutRect& aBounds);
@@ -465,69 +458,33 @@ public:
const wr::LayoutRect& aBoxBounds,
const wr::LayoutVector2D& aOffset,
const wr::ColorF& aColor,
const float& aBlurRadius,
const float& aSpreadRadius,
const wr::BorderRadius& aBorderRadius,
const wr::BoxShadowClipMode& aClipMode);
- // Returns the clip id that was most recently pushed with PushClip and that
- // has not yet been popped with PopClip. Return Nothing() if the clip stack
- // is empty.
- Maybe<wr::WrClipId> TopmostClipId();
- // Same as TopmostClipId() but for scroll layers.
- wr::WrScrollId TopmostScrollId();
- // If the topmost item on the stack is a clip or a scroll layer
- bool TopmostIsClip();
-
// Set the hit-test info to be used for all display items until the next call
// to SetHitTestInfo or ClearHitTestInfo.
void SetHitTestInfo(const layers::FrameMetrics::ViewID& aScrollId,
gfx::CompositorHitTestInfo aHitInfo);
// Clears the hit-test info so that subsequent display items will not have it.
void ClearHitTestInfo();
// Try to avoid using this when possible.
wr::WrState* Raw() { return mWrState; }
- // Return true if the current clip stack has any extra clip.
- bool HasExtraClip() { return !mCacheOverride.empty(); }
-
protected:
- void PushCacheOverride(const DisplayItemClipChain* aParent,
- const wr::WrClipId& aClipId);
- void PopCacheOverride(const DisplayItemClipChain* aParent);
-
wr::WrState* mWrState;
- // Track the stack of clip ids and scroll layer ids that have been pushed
- // (by PushClip and PushScrollLayer/PushClipAndScrollInfo, respectively) and
- // haven't yet been popped.
- std::vector<wr::ScrollOrClipId> mClipStack;
-
// Track each scroll id that we encountered. We use this structure to
// ensure that we don't define a particular scroll layer multiple times,
// as that results in undefined behaviour in WR.
- std::unordered_map<layers::FrameMetrics::ViewID, wr::WrScrollId> mScrollIds;
-
- // A map that holds the cache overrides creates by "out of band" clips, i.e.
- // clips that are generated by display items but that ScrollingLayersHelper
- // doesn't know about. These are called "cache overrides" because while we're
- // inside one of these clips, the WR clip stack is different from what
- // ScrollingLayersHelper thinks it actually is (because of the out-of-band
- // clip that was pushed onto the stack) and so ScrollingLayersHelper cannot
- // use its clip cache as-is. Instead, any time ScrollingLayersHelper wants
- // to define a new clip as a child of clip X, it should first check the
- // cache overrides to see if there is an out-of-band clip Y that is already a
- // child of X, and then define its clip as a child of Y instead. This map
- // stores X -> ClipId of Y, which allows ScrollingLayersHelper to do the
- // necessary lookup. Note that there theoretically might be multiple
- // different "Y" clips which is why we need a vector.
- std::unordered_map<const DisplayItemClipChain*, std::vector<wr::WrClipId>> mCacheOverride;
+ std::unordered_map<layers::FrameMetrics::ViewID, wr::WrClipId> mScrollIds;
friend class WebRenderAPI;
};
Maybe<wr::ImageFormat>
SurfaceFormatToImageFormat(gfx::SurfaceFormat aFormat);
} // namespace wr
--- a/gfx/webrender_bindings/WebRenderTypes.cpp
+++ b/gfx/webrender_bindings/WebRenderTypes.cpp
@@ -27,14 +27,15 @@ Assign_WrVecU8(wr::WrVecU8& aVec, mozill
aVec.data = aOther.mData;
aVec.length = aOther.mLen;
aVec.capacity = aOther.mCapacity;
aOther.mData = nullptr;
aOther.mLen = 0;
aOther.mCapacity = 0;
}
-WrScrollId WrScrollId::RootScrollNode() {
- return WrScrollId { wr_root_scroll_node_id() };
+/*static*/ WrClipId
+WrClipId::RootScrollNode() {
+ return WrClipId { wr_root_scroll_node_id() };
}
} // namespace wr
} // namespace mozilla
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -753,54 +753,52 @@ static inline wr::WrFilterOpType ToWrFil
}
MOZ_ASSERT_UNREACHABLE("Tried to convert unknown filter type.");
return wr::WrFilterOpType::Grayscale;
}
// Corresponds to an "internal" webrender clip id. That is, a
// ClipId::Clip(x,pipeline_id) maps to a WrClipId{x}. We use a struct wrapper
// instead of a typedef so that this is a distinct type from ids generated
-// by scroll and position:sticky nodes and the compiler will catch accidental
+// by scroll and position:sticky nodes and the compiler will catch accidental
// conversions between them.
struct WrClipId {
size_t id;
bool operator==(const WrClipId& other) const {
return id == other.id;
}
-};
-// Corresponds to a clip id for for a scroll frame in webrender. Similar
-// to WrClipId but a separate struct so we don't get them mixed up in C++.
-struct WrScrollId {
- size_t id;
-
- bool operator==(const WrScrollId& other) const {
- return id == other.id;
+ bool operator!=(const WrClipId& other) const {
+ return !(*this == other);
}
- bool operator!=(const WrScrollId& other) const {
- return id != other.id;
- }
+ static WrClipId RootScrollNode();
- static WrScrollId RootScrollNode();
+ // Helper struct that allows this class to be used as a key in
+ // std::unordered_map like so:
+ // std::unordered_map<WrClipId, ValueType, WrClipId::HashFn> myMap;
+ struct HashFn {
+ std::size_t operator()(const WrClipId& aKey) const
+ {
+ return std::hash<size_t>{}(aKey.id);
+ }
+ };
};
-// Corresponds to a clip id for a position:sticky clip in webrender. Similar
-// to WrClipId but a separate struct so we don't get them mixed up in C++.
-struct WrStickyId {
- size_t id;
+// Corresponds to a clip id for a clip chain in webrender. Similar to
+// WrClipId but a separate struct so we don't get them mixed up in C++.
+struct WrClipChainId {
+ uint64_t id;
- bool operator==(const WrStickyId& other) const {
+ bool operator==(const WrClipChainId& other) const {
return id == other.id;
}
};
-typedef Variant<WrScrollId, WrClipId> ScrollOrClipId;
-
enum class WebRenderError : int8_t {
INITIALIZE = 0,
MAKE_CURRENT,
RENDER,
Sentinel /* this must be last for serialization purposes. */
};
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1653,16 +1653,30 @@ pub extern "C" fn wr_dp_push_stacking_co
#[no_mangle]
pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState) {
debug_assert!(unsafe { !is_in_render_thread() });
state.frame_builder.dl_builder.pop_stacking_context();
}
#[no_mangle]
+pub extern "C" fn wr_dp_define_clipchain(state: &mut WrState,
+ parent_clipchain_id: *const u64,
+ clips: *const usize,
+ clips_count: usize)
+ -> u64 {
+ debug_assert!(unsafe { is_in_main_thread() });
+ let parent = unsafe { parent_clipchain_id.as_ref() }.map(|id| ClipChainId(*id, state.pipeline_id));
+ let clips_slice : Vec<ClipId> = make_slice(clips, clips_count).iter().map(|id| ClipId::Clip(*id, state.pipeline_id)).collect();
+ let clipchain_id = state.frame_builder.dl_builder.define_clip_chain(parent, clips_slice);
+ assert!(clipchain_id.1 == state.pipeline_id);
+ clipchain_id.0
+}
+
+#[no_mangle]
pub extern "C" fn wr_dp_define_clip(state: &mut WrState,
parent_id: *const usize,
clip_rect: LayoutRect,
complex: *const ComplexClipRegion,
complex_count: usize,
mask: *const WrImageMask)
-> usize {
debug_assert!(unsafe { is_in_main_thread() });
@@ -1784,24 +1798,24 @@ pub extern "C" fn wr_dp_push_scroll_laye
pub extern "C" fn wr_dp_pop_scroll_layer(state: &mut WrState) {
debug_assert!(unsafe { is_in_main_thread() });
state.frame_builder.dl_builder.pop_clip_id();
}
#[no_mangle]
pub extern "C" fn wr_dp_push_clip_and_scroll_info(state: &mut WrState,
scroll_id: usize,
- clip_id: *const usize) {
+ clip_chain_id: *const u64) {
debug_assert!(unsafe { is_in_main_thread() });
- let clip_id = unsafe { clip_id.as_ref() };
- let info = if let Some(&cid) = clip_id {
+ let clip_chain_id = unsafe { clip_chain_id.as_ref() };
+ let info = if let Some(&ccid) = clip_chain_id {
ClipAndScrollInfo::new(
ClipId::Clip(scroll_id, state.pipeline_id),
- ClipId::Clip(cid, state.pipeline_id))
+ ClipId::ClipChain(ClipChainId(ccid, state.pipeline_id)))
} else {
ClipAndScrollInfo::simple(
ClipId::Clip(scroll_id, state.pipeline_id))
};
state.frame_builder.dl_builder.push_clip_and_scroll_info(info);
}
#[no_mangle]
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -1113,16 +1113,23 @@ uintptr_t wr_dp_define_clip(WrState *aSt
const uintptr_t *aParentId,
LayoutRect aClipRect,
const ComplexClipRegion *aComplex,
uintptr_t aComplexCount,
const WrImageMask *aMask)
WR_FUNC;
WR_INLINE
+uint64_t wr_dp_define_clipchain(WrState *aState,
+ const uint64_t *aParentClipchainId,
+ const uintptr_t *aClips,
+ uintptr_t aClipsCount)
+WR_FUNC;
+
+WR_INLINE
uintptr_t wr_dp_define_scroll_layer(WrState *aState,
uint64_t aScrollId,
const uintptr_t *aParentId,
LayoutRect aContentRect,
LayoutRect aClipRect)
WR_FUNC;
WR_INLINE
@@ -1233,17 +1240,17 @@ WR_FUNC;
WR_INLINE
void wr_dp_push_clip(WrState *aState,
uintptr_t aClipId)
WR_FUNC;
WR_INLINE
void wr_dp_push_clip_and_scroll_info(WrState *aState,
uintptr_t aScrollId,
- const uintptr_t *aClipId)
+ const uint64_t *aClipChainId)
WR_FUNC;
WR_INLINE
void wr_dp_push_iframe(WrState *aState,
LayoutRect aRect,
bool aIsBackfaceVisible,
WrPipelineId aPipelineId)
WR_FUNC;
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -561,17 +561,17 @@ BulletRenderer::CreateWebRenderCommandsF
return true;
}
case NS_STYLE_LIST_STYLE_DISC: {
nsTArray<wr::ComplexClipRegion> clips;
clips.AppendElement(wr::ToComplexClipRegion(
RoundedRect(ThebesRect(mPathRect.ToUnknownRect()),
RectCornerRadii(dest.size.width / 2.0))
));
- auto clipId = aBuilder.DefineClip(Nothing(), Nothing(), dest, &clips, nullptr);
+ auto clipId = aBuilder.DefineClip(Nothing(), dest, &clips, nullptr);
aBuilder.PushClip(clipId);
aBuilder.PushRect(dest, dest, isBackfaceVisible, color);
aBuilder.PopClip();
return true;
}
case NS_STYLE_LIST_STYLE_SQUARE: {
aBuilder.PushRect(dest, dest, isBackfaceVisible, color);
return true;
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -148,17 +148,16 @@ public:
WebRenderCanvasRendererAsync* data =
static_cast<WebRenderCanvasRendererAsync*>(canvasData->GetCanvasRenderer());
MOZ_ASSERT(data);
data->UpdateCompositableClient();
// Push IFrame for async image pipeline.
// XXX Remove this once partial display list update is supported.
- /* ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc); */
nsIntSize canvasSizeInPx = data->GetSize();
IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSizeInPx);
nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSizeInPx);
nsRect area = mFrame->GetContentRectRelativeToSelf() + ToReferenceFrame();
nsRect dest =
nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, intrinsicRatio,
mFrame->StylePosition());
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -3435,30 +3435,30 @@ nsCSSBorderRenderer::CreateWebRenderComm
wr::BorderRadius borderRadius = wr::ToBorderRadius(LayoutDeviceSize::FromUnknownSize(mBorderRadii[0]),
LayoutDeviceSize::FromUnknownSize(mBorderRadii[1]),
LayoutDeviceSize::FromUnknownSize(mBorderRadii[3]),
LayoutDeviceSize::FromUnknownSize(mBorderRadii[2]));
if (mLocalClip) {
LayoutDeviceRect clip = LayoutDeviceRect::FromUnknownRect(mLocalClip.value());
wr::LayoutRect clipRect = wr::ToRoundedLayoutRect(clip);
- wr::WrClipId clipId = aBuilder.DefineClip(Nothing(), Nothing(), clipRect);
- aBuilder.PushClip(clipId, aItem->GetClipChain());
+ wr::WrClipId clipId = aBuilder.DefineClip(Nothing(), clipRect);
+ aBuilder.PushClip(clipId);
}
Range<const wr::BorderSide> wrsides(side, 4);
aBuilder.PushBorder(roundedRect,
roundedRect,
mBackfaceIsVisible,
wr::ToBorderWidths(mBorderWidths[0], mBorderWidths[1], mBorderWidths[2], mBorderWidths[3]),
wrsides,
borderRadius);
if (mLocalClip) {
- aBuilder.PopClip(aItem->GetClipChain());
+ aBuilder.PopClip();
}
}
/* static */Maybe<nsCSSBorderImageRenderer>
nsCSSBorderImageRenderer::CreateBorderImageRenderer(nsPresContext* aPresContext,
nsIFrame* aForFrame,
const nsRect& aBorderArea,
const nsStyleBorder& aStyleBorder,
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -7643,29 +7643,31 @@ nsDisplayStickyPosition::CreateWebRender
}
}
LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(itemBounds, auPerDevPixel);
wr::LayoutVector2D applied = {
NSAppUnitsToFloatPixels(appliedOffset.x, auPerDevPixel),
NSAppUnitsToFloatPixels(appliedOffset.y, auPerDevPixel)
};
- wr::WrStickyId id = aBuilder.DefineStickyFrame(wr::ToRoundedLayoutRect(bounds),
+ wr::WrClipId id = aBuilder.DefineStickyFrame(wr::ToRoundedLayoutRect(bounds),
topMargin.ptrOr(nullptr), rightMargin.ptrOr(nullptr),
bottomMargin.ptrOr(nullptr), leftMargin.ptrOr(nullptr),
vBounds, hBounds, applied);
- aBuilder.PushStickyFrame(id, GetClipChain());
+ aBuilder.PushClip(id);
+ aManager->CommandBuilder().PushOverrideForASR(GetActiveScrolledRoot(), Some(id));
}
nsDisplayOwnLayer::CreateWebRenderCommands(aBuilder, aResources, aSc,
aManager, aDisplayListBuilder);
if (stickyScrollContainer) {
- aBuilder.PopStickyFrame(GetClipChain());
+ aManager->CommandBuilder().PopOverrideForASR(GetActiveScrolledRoot());
+ aBuilder.PopClip();
}
return true;
}
nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
nsDisplayListBuilder* aBuilder,
nsIFrame* aScrolledFrame,
@@ -9699,17 +9701,17 @@ nsDisplayMask::CreateWebRenderCommands(m
Maybe<wr::WrImageMask> mask = aManager->CommandBuilder().BuildWrMaskImage(this, aBuilder, aResources,
aSc, aDisplayListBuilder,
bounds);
Maybe<StackingContextHelper> layer;
const StackingContextHelper* sc = &aSc;
if (mask) {
auto layoutBounds = wr::ToRoundedLayoutRect(bounds);
- wr::WrClipId clipId = aBuilder.DefineClip(Nothing(), Nothing(),
+ wr::WrClipId clipId = aBuilder.DefineClip(Nothing(),
layoutBounds, nullptr, mask.ptr());
// Create a new stacking context to attach the mask to, ensuring the mask is
// applied to the aggregate, and not the individual elements.
// The stacking context shouldn't have any offset.
bounds.MoveTo(0, 0);
@@ -9723,20 +9725,25 @@ nsDisplayMask::CreateWebRenderCommands(m
/*aTransform: */ nullptr,
/*aPerspective: */ nullptr,
/*aMixBlendMode: */ gfx::CompositionOp::OP_OVER,
/*aBackfaceVisible: */ true,
/*aIsPreserve3D: */ false,
/*aTransformForScrollData: */ Nothing(),
/*aClipNodeId: */ &clipId);
sc = layer.ptr();
+ aManager->CommandBuilder().PushOverrideForASR(GetActiveScrolledRoot(), Some(clipId));
}
nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, *sc, aManager, aDisplayListBuilder);
+ if (mask) {
+ aManager->CommandBuilder().PopOverrideForASR(GetActiveScrolledRoot());
+ }
+
return true;
}
Maybe<nsRect>
nsDisplayMask::GetClipWithRespectToASR(nsDisplayListBuilder* aBuilder,
const ActiveScrolledRoot* aASR) const
{
if (const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(GetClipChain(), aASR)) {
--- a/layout/reftests/async-scrolling/reftest.list
+++ b/layout/reftests/async-scrolling/reftest.list
@@ -52,18 +52,18 @@ fuzzy-if(Android,7,4) skip-if(!asyncPan)
fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-2.html perspective-scrolling-2-ref.html
fuzzy-if(Android,7,4) fails-if(webrender) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html # bug 1361720 for webrender
fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-4.html perspective-scrolling-4-ref.html
pref(apz.disable_for_scroll_linked_effects,true) skip-if(!asyncPan) == disable-apz-for-sle-pages.html disable-apz-for-sle-pages-ref.html
fuzzy-if(browserIsRemote&&d2d,1,20) skip-if(!asyncPan) == background-blend-mode-1.html background-blend-mode-1-ref.html
skip-if(Android||!asyncPan) != opaque-fractional-displayport-1.html about:blank
skip-if(Android||!asyncPan) != opaque-fractional-displayport-2.html about:blank
fuzzy-if(Android,6,4) skip-if(!asyncPan) == fixed-pos-scrolled-clip-1.html fixed-pos-scrolled-clip-1-ref.html
-fuzzy-if(Android,6,8) fails-if(webrender) skip-if(!asyncPan) == fixed-pos-scrolled-clip-2.html fixed-pos-scrolled-clip-2-ref.html # bug 1377187 for webrender
-fuzzy-if(Android,6,8) fails-if(webrender) skip-if(!asyncPan) == fixed-pos-scrolled-clip-3.html fixed-pos-scrolled-clip-3-ref.html # bug 1377187 for webrender
+fuzzy-if(Android,6,8) skip-if(!asyncPan) == fixed-pos-scrolled-clip-2.html fixed-pos-scrolled-clip-2-ref.html
+fuzzy-if(Android,6,8) fails-if(webrender) skip-if(!asyncPan) == fixed-pos-scrolled-clip-3.html fixed-pos-scrolled-clip-3-ref.html # bug 1458598 for webrender
fuzzy-if(Android,6,8) skip-if(!asyncPan) == fixed-pos-scrolled-clip-4.html fixed-pos-scrolled-clip-4-ref.html
skip-if(!asyncPan) == fixed-pos-scrolled-clip-5.html fixed-pos-scrolled-clip-5-ref.html
skip-if(!asyncPan) == position-sticky-bug1434250.html position-sticky-bug1434250-ref.html
fuzzy-if(Android,6,4) skip-if(!asyncPan) == position-sticky-scrolled-clip-1.html position-sticky-scrolled-clip-1-ref.html
fuzzy-if(Android,6,4) skip == position-sticky-scrolled-clip-2.html position-sticky-scrolled-clip-2-ref.html # bug ?????? - incorrectly applying clip to sticky contents
skip-if(!asyncPan) == curtain-effect-1.html curtain-effect-1-ref.html
# for the following tests, we want to disable the low-precision buffer
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -167,17 +167,17 @@ fuzzy(50,500) fuzzy-if(skiaContent,51,32
== attachment-local-clipping-image-2.html attachment-local-clipping-image-1-ref.html # Same ref as the previous test.
== attachment-local-clipping-image-3.html attachment-local-clipping-image-3-ref.html
# The next three tests are fuzzy due to bug 1128229.
fuzzy(16,69) fuzzy-if(skiaContent,95,2206) == attachment-local-clipping-image-4.html attachment-local-clipping-image-4-ref.html
fuzzy(16,69) fuzzy-if(skiaContent,95,2206) == attachment-local-clipping-image-5.html attachment-local-clipping-image-4-ref.html
fuzzy(80,500) fuzzy-if(skiaContent,109,908) == attachment-local-clipping-image-6.html attachment-local-clipping-image-6-ref.html
fuzzy-if(skiaContent,1,8) fuzzy-if(webrender,1,84) == background-multiple-with-border-radius.html background-multiple-with-border-radius-ref.html
-fuzzy-if(webrender&&winWidget,73-73,49600-49600) == background-repeat-large-area.html background-repeat-large-area-ref.html
+fuzzy-if(webrender,73-93,49600-49600) == background-repeat-large-area.html background-repeat-large-area-ref.html
fuzzy(30,474) fuzzy-if(skiaContent,31,474) == background-tiling-zoom-1.html background-tiling-zoom-1-ref.html
skip-if(!cocoaWidget) == background-repeat-resampling.html background-repeat-resampling-ref.html
fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1a.html background-clip-text-1-ref.html
fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1b.html background-clip-text-1-ref.html
fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1c.html background-clip-text-1-ref.html
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1386,17 +1386,17 @@ pref(dom.use_xbl_scopes_for_remote_xul,t
== 495385-5.html 495385-5-ref.html
== 496032-1.html 496032-1-ref.html
== 496840-1.html 496840-1-ref.html
fuzzy-if(skiaContent,1,17000) == 498228-1.xul 498228-1-ref.xul
== 501037.html 501037-ref.html
== 501257-1a.html 501257-1-ref.html
== 501257-1b.html 501257-1-ref.html
== 501257-1.xhtml 501257-1-ref.xhtml
-fuzzy-if(webrender&&winWidget,5-5,83252-83252) == 501627-1.html 501627-1-ref.html
+fuzzy-if(webrender,5-6,83252-97456) == 501627-1.html 501627-1-ref.html
== 502288-1.html 502288-1-ref.html
fuzzy-if(gtkWidget,1,2) == 502447-1.html 502447-1-ref.html #Bug 1315834
== 502795-1.html 502795-1-ref.html
== 502942-1.html 502942-1-ref.html
== 503364-1a.html 503364-1-ref.html
== 503364-1b.html 503364-1-ref.html
# Reftest for bug 503531 marked as failing; should be re-enabled when
# bug 607548 gets resolved.
@@ -1767,17 +1767,17 @@ fuzzy-if(Android,4,400) == 815593-1.html
fuzzy-if(skiaContent,1,5) == 816948-1.html 816948-1-ref.html
== 817019-1.html about:blank
fuzzy-if(skiaContent,1,5) == 818276-1.html 818276-1-ref.html
fuzzy-if(asyncPan,190,510) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,510) == 825999.html 825999-ref.html
== 827577-1a.html 827577-1-ref.html
== 827577-1b.html 827577-1-ref.html
== 827799-1.html about:blank
== 829958.html 829958-ref.html
-== 836844-1.html 836844-1-ref.html
+fuzzy-if(webrender&>kWidget,1-2,44000-135600) == 836844-1.html 836844-1-ref.html
== 841192-1.html 841192-1-ref.html
== 844178.html 844178-ref.html
fuzzy-if(OSX,1,364) fuzzy-if(skiaContent,1,320) == 846144-1.html 846144-1-ref.html
== 847850-1.html 847850-1-ref.html
== 848421-1.html 848421-1-ref.html
== 849407-1.html 849407-1-ref.html
== 849996-1.html 849996-1-ref.html
== 858803-1.html 858803-1-ref.html
@@ -1812,17 +1812,17 @@ fuzzy-if(Android,1,1) fuzzy-if(skiaConte
fuzzy-if(skiaContent,1,5) == 956513-1.svg 956513-1-ref.svg
== 944291-1.html 944291-1-ref.html
== 950436-1.html 950436-1-ref.html
== 957770-1.svg 957770-1-ref.svg
== 960277-1.html 960277-1-ref.html
fuzzy-if(skiaContent,1,80) == 961887-1.html 961887-1-ref.html
== 961887-2.html 961887-2-ref.html
== 961887-3.html 961887-3-ref.html
-pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,145) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,3712) fails-if(webrender) == 966992-1.html 966992-1-ref.html
+pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,145) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,3712) == 966992-1.html 966992-1-ref.html
skip-if(Android) == 966510-1.html 966510-1-ref.html # scrollable elements other than the root probably won't work well on android until bug 776030 is fixed
skip-if(Android) == 966510-2.html 966510-2-ref.html # same as above
fuzzy-if(skiaContent,1,123) == 978911-1.svg 978911-1-ref.svg
== 983084-1.html 983084-1-ref.html
== 983084-2.html 983084-2-ref.html
== 983084-3.html 983084-1-ref.html
== 983691-1.html 983691-ref.html
== 983985-1.html 983985-1-ref.html
--- a/layout/reftests/forms/placeholder/reftest.list
+++ b/layout/reftests/forms/placeholder/reftest.list
@@ -11,17 +11,17 @@
== placeholder-1-text.html placeholder-visible-ref.html
== placeholder-1-password.html placeholder-visible-ref.html
== placeholder-1-textarea.html placeholder-visible-textarea-ref.html
== placeholder-2.html placeholder-visible-ref.html
== placeholder-2-textarea.html placeholder-visible-textarea-ref.html
== placeholder-3.html placeholder-overridden-ref.html
== placeholder-4.html placeholder-overridden-ref.html
== placeholder-5.html placeholder-visible-ref.html
-fuzzy-if(winWidget,160,10) fuzzy-if(Android,1,1) fuzzy-if(asyncPan&&!layersGPUAccelerated,146,317) fuzzy-if(OSX==1010&&browserIsRemote,1,8) fails-if(webrender) == placeholder-6.html placeholder-overflow-ref.html
+fuzzy-if(winWidget,160,10) fuzzy-if(Android,1,1) fuzzy-if(asyncPan&&!layersGPUAccelerated,146,317) fuzzy-if(OSX==1010&&browserIsRemote,1,8) == placeholder-6.html placeholder-overflow-ref.html
skip-if(Android&&asyncPan) == placeholder-6-textarea.html placeholder-overflow-textarea-ref.html
# needs-focus == placeholder-7.html placeholder-focus-ref.html
# needs-focus == placeholder-8.html placeholder-focus-ref.html
# needs-focus == placeholder-9.html placeholder-focus-ref.html
needs-focus == placeholder-10.html placeholder-visible-ref.html
== placeholder-11.html placeholder-visible-ref.html
== placeholder-12.html placeholder-visible-ref.html
== placeholder-13.html placeholder-visible-ref.html
--- a/layout/reftests/forms/textarea/reftest.list
+++ b/layout/reftests/forms/textarea/reftest.list
@@ -5,10 +5,10 @@ skip-if(Android) != ltr.html rtl.html
skip-if(Android) != ltr-scrollbar.html rtl-scrollbar.html
skip-if(Android) != in-ltr-doc-scrollbar.html in-rtl-doc-scrollbar.html
skip-if(Android) != ltr.html no-resize.html
skip-if(Android) != rtl.html no-resize.html # bug 834724
fuzzy-if(skiaContent,1,1) == rtl.html rtl-dynamic-attr.html
fuzzy-if(skiaContent,1,1) == rtl.html rtl-dynamic-style.html
== rtl.html in-dynamic-rtl-doc.html
fuzzy-if(skiaContent,1,3) == setvalue-framereconstruction-1.html setvalue-framereconstruction-ref.html
-fuzzy-if(asyncPan&&!layersGPUAccelerated,102,4168) fails-if(webrender) == padding-scrollbar-placement.html padding-scrollbar-placement-ref.html
+fuzzy-if(asyncPan&&!layersGPUAccelerated,102,4168) == padding-scrollbar-placement.html padding-scrollbar-placement-ref.html
== various-cols.html various-cols-ref.html
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -4085,17 +4085,17 @@ nsWindow::AddWindowOverlayWebRenderComma
{
if (mWindowButtonsRect) {
wr::LayoutRect rect = wr::ToLayoutRect(*mWindowButtonsRect);
nsTArray<wr::ComplexClipRegion> roundedClip;
roundedClip.AppendElement(wr::ToComplexClipRegion(
RoundedRect(ThebesRect(mWindowButtonsRect->ToUnknownRect()),
RectCornerRadii(0, 0, 3, 3))));
wr::WrClipId clipId =
- aBuilder.DefineClip(Nothing(), Nothing(), rect, &roundedClip);
+ aBuilder.DefineClip(Nothing(), rect, &roundedClip);
aBuilder.PushClip(clipId);
aBuilder.PushClearRect(rect);
aBuilder.PopClip();
}
}
uint32_t
nsWindow::GetMaxTouchPoints() const