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