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_STACKINGCONTEXTHELPER_H 8 #define GFX_STACKINGCONTEXTHELPER_H 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/gfx/MatrixFwd.h" 12 #include "mozilla/webrender/WebRenderAPI.h" 13 #include "mozilla/webrender/WebRenderTypes.h" 14 #include "Units.h" 15 16 class nsDisplayTransform; 17 18 namespace mozilla { 19 20 struct ActiveScrolledRoot; 21 22 namespace layers { 23 24 /** 25 * This is a helper class that pushes/pops a stacking context, and manages 26 * some of the coordinate space transformations needed. 27 */ 28 class MOZ_RAII StackingContextHelper { 29 public: 30 StackingContextHelper(const StackingContextHelper& aParentSC, 31 const ActiveScrolledRoot* aAsr, 32 nsIFrame* aContainerFrame, 33 nsDisplayItem* aContainerItem, 34 wr::DisplayListBuilder& aBuilder, 35 const wr::StackingContextParams& aParams, 36 const LayoutDeviceRect& aBounds = LayoutDeviceRect()); 37 38 // This version of the constructor should only be used at the root level 39 // of the tree, so that we have a StackingContextHelper to pass down into 40 // the RenderLayer traversal, but don't actually want it to push a stacking 41 // context on the display list builder. 42 StackingContextHelper(); 43 44 // Pops the stacking context, if one was pushed during the constructor. 45 ~StackingContextHelper(); 46 47 // Export the inherited scale GetInheritedScale()48 gfx::Size GetInheritedScale() const { return mScale; } 49 GetInheritedTransform()50 const gfx::Matrix& GetInheritedTransform() const { 51 return mInheritedTransform; 52 } 53 GetSnappingSurfaceTransform()54 const gfx::Matrix& GetSnappingSurfaceTransform() const { 55 return mSnappingSurfaceTransform; 56 } 57 58 const Maybe<nsDisplayTransform*>& GetDeferredTransformItem() const; 59 Maybe<gfx::Matrix4x4> GetDeferredTransformMatrix() const; 60 AffectsClipPositioning()61 bool AffectsClipPositioning() const { return mAffectsClipPositioning; } ReferenceFrameId()62 Maybe<wr::WrSpatialId> ReferenceFrameId() const { return mReferenceFrameId; } 63 GetOrigin()64 const LayoutDevicePoint& GetOrigin() const { return mOrigin; } 65 66 private: 67 wr::DisplayListBuilder* mBuilder; 68 gfx::Size mScale; 69 gfx::Matrix mInheritedTransform; 70 LayoutDevicePoint mOrigin; 71 72 // The "snapping surface" defines the space that we want to snap in. 73 // You can think of it as the nearest physical surface. 74 // Animated transforms create a new snapping surface, so that changes to their 75 // transform don't affect the snapping of their contents. Non-animated 76 // transforms do *not* create a new snapping surface, so that for example the 77 // existence of a non-animated identity transform does not affect snapping. 78 gfx::Matrix mSnappingSurfaceTransform; 79 bool mAffectsClipPositioning; 80 Maybe<wr::WrSpatialId> mReferenceFrameId; 81 Maybe<wr::SpaceAndClipChainHelper> mSpaceAndClipChainHelper; 82 83 // The deferred transform item is used when building the WebRenderScrollData 84 // structure. The backstory is that APZ needs to know about transforms that 85 // apply to the different APZC instances. Prior to bug 1423370, we would do 86 // this by creating a new WebRenderLayerScrollData for each nsDisplayTransform 87 // item we encountered. However, this was unnecessarily expensive because it 88 // turned out a lot of nsDisplayTransform items didn't have new ASRs defined 89 // as descendants, so we'd create the WebRenderLayerScrollData and send it 90 // over to APZ even though the transform information was not needed in that 91 // case. 92 // 93 // In bug 1423370 and friends, this was optimized by "deferring" a 94 // nsDisplayTransform item when we encountered it during display list 95 // traversal. If we found a descendant of that transform item that had a 96 // new ASR or otherwise was "relevant to APZ", we would then pluck the 97 // transform matrix off the deferred item and put it on the 98 // WebRenderLayerScrollData instance created for that APZ-relevant descendant. 99 // 100 // One complication with this is if there are multiple nsDisplayTransform 101 // items in the ancestor chain for the APZ-relevant item. As we traverse the 102 // display list, we will defer the outermost nsDisplayTransform item, and when 103 // we encounter the next one we will need to merge it with the already- 104 // deferred one somehow. What we do in this case is have 105 // mDeferredTransformItem always point to the "innermost" deferred transform 106 // item (i.e. the closest ancestor nsDisplayTransform item of the item that 107 // created this StackingContextHelper). And then we use 108 // mDeferredAncestorTransform to store the product of all the other transforms 109 // that were deferred. As a result, there is an invariant here that if 110 // mDeferredTransformItem is Nothing(), mDeferredAncestorTransform will also 111 // be Nothing(). Note that we can only do this if the nsDisplayTransform items 112 // share the same ASR. If we are processing an nsDisplayTransform item with a 113 // different ASR than the previously-deferred item, we assume that the 114 // previously-deferred transform will get sent to APZ as part of a separate 115 // WebRenderLayerScrollData item, and so we don't need to bother with any 116 // merging. (The merging probably wouldn't even make sense because the 117 // coordinate spaces might be different in the face of async scrolling). This 118 // behaviour of forcing a WebRenderLayerScrollData item to be generated when 119 // the ASR changes is implemented in 120 // WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList. 121 Maybe<nsDisplayTransform*> mDeferredTransformItem; 122 Maybe<gfx::Matrix4x4> mDeferredAncestorTransform; 123 124 bool mRasterizeLocally; 125 }; 126 127 } // namespace layers 128 } // namespace mozilla 129 130 #endif /* GFX_STACKINGCONTEXTHELPER_H */ 131