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