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/. */
7 #include "FrameMetrics.h"
12 #include "nsStyleConsts.h"
13 #include "mozilla/gfx/Types.h"
18 const ScrollableLayerGuid::ViewID
ScrollableLayerGuid::NULL_SCROLL_ID
= 0;
20 std::ostream
& operator<<(std::ostream
& aStream
, const FrameMetrics
& aMetrics
) {
21 aStream
<< "{ [cb=" << aMetrics
.GetCompositionBounds()
22 << "] [sr=" << aMetrics
.GetScrollableRect()
23 << "] [s=" << aMetrics
.GetVisualScrollOffset();
24 if (aMetrics
.GetVisualScrollUpdateType() != FrameMetrics::eNone
) {
25 aStream
<< "] [vd=" << aMetrics
.GetVisualDestination();
27 if (aMetrics
.IsScrollInfoLayer()) {
28 aStream
<< "] [scrollinfo";
30 aStream
<< "] [dp=" << aMetrics
.GetDisplayPort()
31 << "] [rcs=" << aMetrics
.GetBoundingCompositionSize()
32 << "] [v=" << aMetrics
.GetLayoutViewport()
33 << nsPrintfCString("] [z=(ld=%.3f r=%.3f",
34 aMetrics
.GetDevPixelsPerCSSPixel().scale
,
35 aMetrics
.GetPresShellResolution())
37 << " cr=" << aMetrics
.GetCumulativeResolution()
38 << " z=" << aMetrics
.GetZoom()
39 << " t=" << aMetrics
.GetTransformToAncestorScale() << " )] [u=("
40 << (int)aMetrics
.GetVisualScrollUpdateType() << " "
41 << aMetrics
.GetScrollGeneration()
42 << ")] scrollId=" << aMetrics
.GetScrollId();
43 if (aMetrics
.IsRootContent()) {
50 void FrameMetrics::RecalculateLayoutViewportOffset() {
51 // For subframes, the visual and layout viewports coincide, so just
52 // keep the layout viewport offset in sync with the visual one.
53 if (!mIsRootContent
) {
54 mLayoutViewport
.MoveTo(GetVisualScrollOffset());
57 // For the root, the two viewports can diverge, but the layout
58 // viewport needs to keep enclosing the visual viewport.
59 KeepLayoutViewportEnclosingVisualViewport(GetVisualViewport(),
60 mScrollableRect
, mLayoutViewport
);
64 void FrameMetrics::KeepLayoutViewportEnclosingVisualViewport(
65 const CSSRect
& aVisualViewport
, const CSSRect
& aScrollableRect
,
66 CSSRect
& aLayoutViewport
) {
67 // If the visual viewport is contained within the layout viewport, we don't
68 // need to make any adjustments, so we can exit early.
70 // Additionally, if the composition bounds changes (due to an orientation
71 // change, window resize, etc.), it may take a few frames for aLayoutViewport
72 // to update and during that time, the visual viewport may be larger than the
73 // layout viewport. In such situations, we take an early exit if the visual
74 // viewport contains the layout viewport.
75 if (aLayoutViewport
.Contains(aVisualViewport
) ||
76 aVisualViewport
.Contains(aLayoutViewport
)) {
80 // If visual viewport size is greater than the layout viewport, move the
81 // layout viewport such that it remains inside the visual viewport. Otherwise,
82 // move the layout viewport such that the visual viewport is contained
83 // inside the layout viewport.
84 if ((aLayoutViewport
.Width() < aVisualViewport
.Width() &&
85 !FuzzyEqualsMultiplicative(aLayoutViewport
.Width(),
86 aVisualViewport
.Width())) ||
87 (aLayoutViewport
.Height() < aVisualViewport
.Height() &&
88 !FuzzyEqualsMultiplicative(aLayoutViewport
.Height(),
89 aVisualViewport
.Height()))) {
90 if (aLayoutViewport
.X() < aVisualViewport
.X()) {
91 // layout viewport moves right
92 aLayoutViewport
.MoveToX(aVisualViewport
.X());
93 } else if (aVisualViewport
.XMost() < aLayoutViewport
.XMost()) {
94 // layout viewport moves left
95 aLayoutViewport
.MoveByX(aVisualViewport
.XMost() -
96 aLayoutViewport
.XMost());
98 if (aLayoutViewport
.Y() < aVisualViewport
.Y()) {
99 // layout viewport moves down
100 aLayoutViewport
.MoveToY(aVisualViewport
.Y());
101 } else if (aVisualViewport
.YMost() < aLayoutViewport
.YMost()) {
102 // layout viewport moves up
103 aLayoutViewport
.MoveByY(aVisualViewport
.YMost() -
104 aLayoutViewport
.YMost());
107 if (aVisualViewport
.X() < aLayoutViewport
.X()) {
108 aLayoutViewport
.MoveToX(aVisualViewport
.X());
109 } else if (aLayoutViewport
.XMost() < aVisualViewport
.XMost()) {
110 aLayoutViewport
.MoveByX(aVisualViewport
.XMost() -
111 aLayoutViewport
.XMost());
113 if (aVisualViewport
.Y() < aLayoutViewport
.Y()) {
114 aLayoutViewport
.MoveToY(aVisualViewport
.Y());
115 } else if (aLayoutViewport
.YMost() < aVisualViewport
.YMost()) {
116 aLayoutViewport
.MoveByY(aVisualViewport
.YMost() -
117 aLayoutViewport
.YMost());
121 // Regardless of any adjustment above, the layout viewport is not allowed
122 // to go outside the scrollable rect.
123 aLayoutViewport
= aLayoutViewport
.MoveInsideAndClamp(aScrollableRect
);
127 CSSRect
FrameMetrics::CalculateScrollRange(
128 const CSSRect
& aScrollableRect
, const ParentLayerRect
& aCompositionBounds
,
129 const CSSToParentLayerScale
& aZoom
) {
130 CSSSize scrollPortSize
=
131 CalculateCompositedSizeInCssPixels(aCompositionBounds
, aZoom
);
132 CSSRect scrollRange
= aScrollableRect
;
133 scrollRange
.SetWidth(
134 std::max(scrollRange
.Width() - scrollPortSize
.width
, 0.0f
));
135 scrollRange
.SetHeight(
136 std::max(scrollRange
.Height() - scrollPortSize
.height
, 0.0f
));
141 CSSSize
FrameMetrics::CalculateCompositedSizeInCssPixels(
142 const ParentLayerRect
& aCompositionBounds
,
143 const CSSToParentLayerScale
& aZoom
) {
144 if (aZoom
== CSSToParentLayerScale(0)) {
145 return CSSSize(); // avoid division by zero
147 return aCompositionBounds
.Size() / aZoom
;
150 std::pair
<bool, CSSPoint
> FrameMetrics::ApplyAbsoluteScrollUpdateFrom(
151 const ScrollPositionUpdate
& aUpdate
) {
152 CSSPoint oldVisualOffset
= GetVisualScrollOffset();
153 // In applying a main-thread scroll update, try to preserve the relative
154 // offset between the visual and layout viewports.
155 CSSPoint relativeOffset
= oldVisualOffset
- GetLayoutScrollOffset();
156 MOZ_ASSERT(IsRootContent() || relativeOffset
== CSSPoint());
157 // We need to set the two offsets together, otherwise a subsequent
158 // RecalculateLayoutViewportOffset() could see divergent layout and
160 bool offsetChanged
= SetLayoutScrollOffset(aUpdate
.GetDestination());
162 ClampAndSetVisualScrollOffset(aUpdate
.GetDestination() + relativeOffset
);
163 return {offsetChanged
, GetVisualScrollOffset() - oldVisualOffset
};
166 CSSPoint
FrameMetrics::ApplyRelativeScrollUpdateFrom(
167 const ScrollPositionUpdate
& aUpdate
) {
168 MOZ_ASSERT(aUpdate
.GetType() == ScrollUpdateType::Relative
);
169 CSSPoint origin
= GetVisualScrollOffset();
170 CSSPoint delta
= (aUpdate
.GetDestination() - aUpdate
.GetSource());
171 ClampAndSetVisualScrollOffset(origin
+ delta
);
172 return GetVisualScrollOffset() - origin
;
175 CSSPoint
FrameMetrics::ApplyPureRelativeScrollUpdateFrom(
176 const ScrollPositionUpdate
& aUpdate
) {
177 MOZ_ASSERT(aUpdate
.GetType() == ScrollUpdateType::PureRelative
);
178 CSSPoint origin
= GetVisualScrollOffset();
179 ClampAndSetVisualScrollOffset(origin
+ aUpdate
.GetDelta());
180 return GetVisualScrollOffset() - origin
;
183 void FrameMetrics::UpdatePendingScrollInfo(const ScrollPositionUpdate
& aInfo
) {
184 // We only get this "pending scroll info" for paint-skip transactions,
185 // but PureRelative position updates always trigger a full paint, so
186 // we should never enter this code with a PureRelative update type. For
187 // the other types, the destination field on the ScrollPositionUpdate will
188 // tell us the final layout scroll position on the main thread.
189 MOZ_ASSERT(aInfo
.GetType() != ScrollUpdateType::PureRelative
);
191 // In applying a main-thread scroll update, try to preserve the relative
192 // offset between the visual and layout viewports.
193 CSSPoint relativeOffset
= GetVisualScrollOffset() - GetLayoutScrollOffset();
194 MOZ_ASSERT(IsRootContent() || relativeOffset
== CSSPoint());
196 SetLayoutScrollOffset(aInfo
.GetDestination());
197 ClampAndSetVisualScrollOffset(aInfo
.GetDestination() + relativeOffset
);
198 mScrollGeneration
= aInfo
.GetGeneration();
201 std::ostream
& operator<<(std::ostream
& aStream
,
202 const OverscrollBehavior
& aBehavior
) {
204 case OverscrollBehavior::Auto
: {
208 case OverscrollBehavior::Contain
: {
209 aStream
<< "contain";
212 case OverscrollBehavior::None
: {
220 OverscrollBehaviorInfo::OverscrollBehaviorInfo()
221 : mBehaviorX(OverscrollBehavior::Auto
),
222 mBehaviorY(OverscrollBehavior::Auto
) {}
224 static OverscrollBehavior
ToOverscrollBehavior(
225 StyleOverscrollBehavior aBehavior
) {
227 case StyleOverscrollBehavior::Auto
:
228 return OverscrollBehavior::Auto
;
229 case StyleOverscrollBehavior::Contain
:
230 return OverscrollBehavior::Contain
;
231 case StyleOverscrollBehavior::None
:
232 return OverscrollBehavior::None
;
234 MOZ_ASSERT_UNREACHABLE("Invalid overscroll behavior");
235 return OverscrollBehavior::Auto
;
238 OverscrollBehaviorInfo
OverscrollBehaviorInfo::FromStyleConstants(
239 StyleOverscrollBehavior aBehaviorX
, StyleOverscrollBehavior aBehaviorY
) {
240 OverscrollBehaviorInfo result
;
241 result
.mBehaviorX
= ToOverscrollBehavior(aBehaviorX
);
242 result
.mBehaviorY
= ToOverscrollBehavior(aBehaviorY
);
246 bool OverscrollBehaviorInfo::operator==(
247 const OverscrollBehaviorInfo
& aOther
) const {
248 return mBehaviorX
== aOther
.mBehaviorX
&& mBehaviorY
== aOther
.mBehaviorY
;
251 std::ostream
& operator<<(std::ostream
& aStream
,
252 const OverscrollBehaviorInfo
& aInfo
) {
253 if (aInfo
.mBehaviorX
== aInfo
.mBehaviorY
) {
254 aStream
<< aInfo
.mBehaviorX
;
256 aStream
<< "{ x=" << aInfo
.mBehaviorX
<< ", y=" << aInfo
.mBehaviorY
<< " }";
261 std::ostream
& operator<<(std::ostream
& aStream
,
262 const ScrollMetadata
& aMetadata
) {
263 aStream
<< "{ [description=" << aMetadata
.GetContentDescription()
264 << "] [metrics=" << aMetadata
.GetMetrics();
265 if (aMetadata
.GetScrollParentId() != ScrollableLayerGuid::NULL_SCROLL_ID
) {
266 aStream
<< "] [scrollParent=" << aMetadata
.GetScrollParentId();
268 if (aMetadata
.GetHasScrollgrab()) {
269 aStream
<< "] [scrollgrab";
271 aStream
<< "] [overscroll=" << aMetadata
.GetOverscrollBehavior() << "] ["
272 << aMetadata
.GetScrollUpdates().Length() << " scrollupdates"
277 StaticAutoPtr
<const ScrollMetadata
> ScrollMetadata::sNullMetadata
;
279 } // namespace layers
280 } // namespace mozilla