summaryrefslogtreecommitdiffstats
path: root/gfx/layers/wr/StackingContextHelper.h
blob: 8239b2db0de81470bd10c56612bdcad16ebe8a78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* -*- 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_STACKINGCONTEXTHELPER_H
#define GFX_STACKINGCONTEXTHELPER_H

#include "mozilla/Attributes.h"
#include "mozilla/gfx/MatrixFwd.h"
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "Units.h"

namespace mozilla {

class nsDisplayTransform;
struct ActiveScrolledRoot;

namespace layers {

/**
 * This is a helper class that pushes/pops a stacking context, and manages
 * some of the coordinate space transformations needed.
 */
class MOZ_RAII StackingContextHelper {
 public:
  StackingContextHelper(const StackingContextHelper& aParentSC,
                        const ActiveScrolledRoot* aAsr,
                        nsIFrame* aContainerFrame,
                        nsDisplayItem* aContainerItem,
                        wr::DisplayListBuilder& aBuilder,
                        const wr::StackingContextParams& aParams,
                        const LayoutDeviceRect& aBounds = LayoutDeviceRect());

  // This version of the constructor should only be used at the root level
  // of the tree, so that we have a StackingContextHelper to pass down into
  // the RenderLayer traversal, but don't actually want it to push a stacking
  // context on the display list builder.
  StackingContextHelper();

  // Pops the stacking context, if one was pushed during the constructor.
  ~StackingContextHelper();

  // Export the inherited scale
  gfx::MatrixScales GetInheritedScale() const { return mScale; }

  const gfx::Matrix& GetInheritedTransform() const {
    return mInheritedTransform;
  }

  const gfx::Matrix& GetSnappingSurfaceTransform() const {
    return mSnappingSurfaceTransform;
  }

  nsDisplayTransform* GetDeferredTransformItem() const;
  Maybe<gfx::Matrix4x4> GetDeferredTransformMatrix() const;
  // Functions for temporarily clearing and restoring the deferred
  // transform item during WebRender display list building. These are
  // used to ensure deferred transforms are not applied in duplicate
  // to nested nodes in the WebRenderScrollData tree.
  void ClearDeferredTransformItem() const;
  void RestoreDeferredTransformItem(nsDisplayTransform* aItem) const;

  bool AffectsClipPositioning() const { return mAffectsClipPositioning; }
  Maybe<wr::WrSpatialId> ReferenceFrameId() const { return mReferenceFrameId; }

  const LayoutDevicePoint& GetOrigin() const { return mOrigin; }

 private:
  wr::DisplayListBuilder* mBuilder;
  gfx::MatrixScales mScale;
  gfx::Matrix mInheritedTransform;
  LayoutDevicePoint mOrigin;

  // The "snapping surface" defines the space that we want to snap in.
  // You can think of it as the nearest physical surface.
  // Animated transforms create a new snapping surface, so that changes to their
  // transform don't affect the snapping of their contents. Non-animated
  // transforms do *not* create a new snapping surface, so that for example the
  // existence of a non-animated identity transform does not affect snapping.
  gfx::Matrix mSnappingSurfaceTransform;
  bool mAffectsClipPositioning;
  Maybe<wr::WrSpatialId> mReferenceFrameId;
  Maybe<wr::SpaceAndClipChainHelper> mSpaceAndClipChainHelper;

  // The deferred transform item is used when building the WebRenderScrollData
  // structure. The backstory is that APZ needs to know about transforms that
  // apply to the different APZC instances. Prior to bug 1423370, we would do
  // this by creating a new WebRenderLayerScrollData for each nsDisplayTransform
  // item we encountered. However, this was unnecessarily expensive because it
  // turned out a lot of nsDisplayTransform items didn't have new ASRs defined
  // as descendants, so we'd create the WebRenderLayerScrollData and send it
  // over to APZ even though the transform information was not needed in that
  // case.
  //
  // In bug 1423370 and friends, this was optimized by "deferring" a
  // nsDisplayTransform item when we encountered it during display list
  // traversal. If we found a descendant of that transform item that had a
  // new ASR or otherwise was "relevant to APZ", we would then pluck the
  // transform matrix off the deferred item and put it on the
  // WebRenderLayerScrollData instance created for that APZ-relevant descendant.
  //
  // One complication with this is if there are multiple nsDisplayTransform
  // items in the ancestor chain for the APZ-relevant item. As we traverse the
  // display list, we will defer the outermost nsDisplayTransform item, and when
  // we encounter the next one we will need to merge it with the already-
  // deferred one somehow. What we do in this case is have
  // mDeferredTransformItem always point to the "innermost" deferred transform
  // item (i.e. the closest ancestor nsDisplayTransform item of the item that
  // created this StackingContextHelper). And then we use
  // mDeferredAncestorTransform to store the product of all the other transforms
  // that were deferred. Note that this means we only need to look at
  // mDeferredAncestorTransform if mDeferredTransformItem is set. Note that we
  // can only do this if the nsDisplayTransform items share the same ASR. If we
  // are processing an nsDisplayTransform item with a different ASR than the
  // previously-deferred item, we assume that the previously-deferred transform
  // will get sent to APZ as part of a separate WebRenderLayerScrollData item,
  // and so we don't need to bother with any merging. (The merging probably
  // wouldn't even make sense because the coordinate spaces might be different
  // in the face of async scrolling). This behaviour of forcing a
  // WebRenderLayerScrollData item to be generated when the ASR changes is
  // implemented in
  // WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList.
  mutable nsDisplayTransform* mDeferredTransformItem;
  Maybe<gfx::Matrix4x4> mDeferredAncestorTransform;

  bool mRasterizeLocally;
};

}  // namespace layers
}  // namespace mozilla

#endif /* GFX_STACKINGCONTEXTHELPER_H */