ClipManager.h (7036B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef GFX_CLIPMANAGER_H 8 #define GFX_CLIPMANAGER_H 9 10 #include <stack> 11 #include <unordered_map> 12 13 #include "mozilla/Attributes.h" 14 #include "mozilla/webrender/WebRenderAPI.h" 15 #include "mozilla/layout/StickyScrollContainer.h" 16 17 namespace mozilla { 18 19 class nsDisplayItem; 20 class nsDisplayStickyPosition; 21 struct ActiveScrolledRoot; 22 struct DisplayItemClipChain; 23 24 namespace wr { 25 class DisplayListBuilder; 26 } 27 28 namespace layers { 29 30 class StackingContextHelper; 31 class WebRenderLayerManager; 32 33 /** 34 * This class manages creating and assigning scroll layers and clips in 35 * WebRender based on the gecko display list. It has a few public functions that 36 * are intended to be invoked while traversing the Gecko display list, and it 37 * uses the ASR and clip information from the display list to create the 38 * necessary clip state in WebRender. 39 * 40 * The structure of the clip state in WebRender ends up quite similar to how 41 * it is in Gecko. For each ASR in Gecko, we create a scroll layer (i.e. a 42 * scrolling clip) in WebRender; these form a tree structure similar to the 43 * ASR tree structure. Ancestors of scroll layers are always other scroll 44 * layers, or the root scroll node. 45 * The DisplayItemClipChain list of clips from the gecko display list is 46 * converted to a WR clip chain and pushed on the stack prior to creating 47 * any WR commands for that item, and is popped afterwards. In addition, 48 * the WR clip chain has a parent pointer, which points to the clip chain for 49 * any enclosing stacking context. This again results in a strucuture very 50 * similar to that in Gecko, where the clips from container display items get 51 * applied to the contained display items. 52 */ 53 class ClipManager { 54 public: 55 ClipManager(); 56 57 void BeginBuild(WebRenderLayerManager* aManager, 58 wr::DisplayListBuilder& aBuilder); 59 void EndBuild(); 60 61 void BeginList(const StackingContextHelper& aStackingContext); 62 void EndList(const StackingContextHelper& aStackingContext); 63 64 wr::WrSpaceAndClipChain SwitchItem(nsDisplayListBuilder* aBuilder, 65 nsDisplayItem* aItem); 66 ~ClipManager(); 67 68 void PushOverrideForASR(const ActiveScrolledRoot* aASR, 69 const wr::WrSpatialId& aSpatialId); 70 void PopOverrideForASR(const ActiveScrolledRoot* aASR); 71 72 private: 73 wr::WrSpatialId SpatialIdAfterOverride(const wr::WrSpatialId& aSpatialId); 74 wr::WrSpatialId GetSpatialId(const ActiveScrolledRoot* aASR); 75 76 static StickyScrollContainer* GetStickyScrollContainer( 77 const ActiveScrolledRoot* aASR); 78 Maybe<wr::WrSpatialId> DefineSpatialNodes(nsDisplayListBuilder* aBuilder, 79 const ActiveScrolledRoot* aASR, 80 nsDisplayItem* aItem); 81 Maybe<wr::WrSpatialId> DefineStickyNode( 82 nsDisplayListBuilder* aBuilder, Maybe<wr::WrSpatialId> aParentSpatialId, 83 const ActiveScrolledRoot* aASR, nsDisplayItem* aItem); 84 85 Maybe<wr::WrClipChainId> DefineClipChain(const DisplayItemClipChain* aChain, 86 int32_t aAppUnitsPerDevPixel); 87 88 WebRenderLayerManager* MOZ_NON_OWNING_REF mManager; 89 wr::DisplayListBuilder* mBuilder; 90 91 // Stack of clip caches. Each cache contains a map from gecko 92 // DisplayItemClipChain objects to webrender WrClipIds, which allows us to 93 // avoid redefining identical clips in WR. However, the gecko 94 // DisplayItemClipChain items get deduplicated quite aggressively, without 95 // regard to things like the enclosing reference frame or mask. On the WR 96 // side, we cannot deduplicate clips that aggressively. So what we do is 97 // any time we enter a new reference frame (for example) we create a new clip 98 // cache on mCacheStack. This ensures we continue caching stuff within a given 99 // reference frame, but disallow caching stuff across reference frames. In 100 // general we need to do this anytime PushOverrideForASR is called, as that is 101 // called for the same set of conditions for which we cannot deduplicate 102 // clips. 103 struct ClipChainCacheEntry { 104 Maybe<wr::WrClipChainId> mWrChainID; 105 }; 106 using ClipIdMap = 107 std::unordered_map<const DisplayItemClipChain*, ClipChainCacheEntry>; 108 std::stack<ClipIdMap> mCacheStack; 109 110 // A map that holds the cache overrides created by (a) "out of band" clips, 111 // i.e. clips that are generated by display items but that ClipManager 112 // doesn't know about and (b) stacking contexts that affect clip positioning. 113 // These are called "cache overrides" because while we're inside these things, 114 // we cannot use the ASR from the gecko display list as-is. Fundamentally this 115 // results from a mismatch between the ASR+clip items on the gecko side and 116 // the ClipScrollTree on the WR side; the WR side incorporates things like 117 // transforms and stacking context origins while the gecko side manages those 118 // differently. 119 // Any time ClipManager wants to define a new clip as a child of ASR X, it 120 // should first check the cache overrides to see if there is a cache override 121 // item ((a) or (b) above) that is already a child of X, and then define that 122 // clip as a child of Y instead. This map stores X -> Y, which allows 123 // ClipManager to do the necessary lookup. Note that there theoretically might 124 // be multiple different "Y" clips (in case of nested cache overrides), which 125 // is why we need a stack. 126 std::unordered_map<wr::WrSpatialId, std::stack<wr::WrSpatialId>> mASROverride; 127 128 // This holds some clip state for a single nsDisplayItem 129 struct ItemClips { 130 ItemClips(const ActiveScrolledRoot* aASR, 131 const DisplayItemClipChain* aChain, int32_t aAppUnitsPerDevPixel, 132 bool aSeparateLeaf); 133 134 // These are the "inputs" - they come from the nsDisplayItem 135 const ActiveScrolledRoot* mASR; 136 const DisplayItemClipChain* mChain; 137 int32_t mAppUnitsPerDevPixel; 138 bool mSeparateLeaf; 139 140 // These are the "outputs" - they are pushed to WR as needed 141 wr::WrSpatialId mScrollId; 142 Maybe<wr::WrClipChainId> mClipChainId; 143 144 void UpdateSeparateLeaf(wr::DisplayListBuilder& aBuilder, 145 int32_t aAppUnitsPerDevPixel); 146 bool HasSameInputs(const ItemClips& aOther); 147 wr::WrSpaceAndClipChain GetSpaceAndClipChain() const; 148 }; 149 150 // A stack of ItemClips corresponding to the nsDisplayItem ancestry. Each 151 // time we recurse into a nsDisplayItem's child list, this stack size 152 // increases by one. The topmost item on the stack is for the display item 153 // we are currently processing and items deeper on the stack are for that 154 // display item's ancestors. 155 std::stack<ItemClips> mItemClipStack; 156 }; 157 158 } // namespace layers 159 } // namespace mozilla 160 161 #endif