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 bool FrameMetrics::ApplyScrollUpdateFrom(const ScrollPositionUpdate
& aUpdate
) {
151 // In applying a main-thread scroll update, try to preserve the relative
152 // offset between the visual and layout viewports.
153 CSSPoint relativeOffset
= GetVisualScrollOffset() - GetLayoutScrollOffset();
154 MOZ_ASSERT(IsRootContent() || relativeOffset
== CSSPoint());
155 // We need to set the two offsets together, otherwise a subsequent
156 // RecalculateLayoutViewportOffset() could see divergent layout and
158 bool offsetChanged
= SetLayoutScrollOffset(aUpdate
.GetDestination());
160 ClampAndSetVisualScrollOffset(aUpdate
.GetDestination() + relativeOffset
);
161 return offsetChanged
;
164 CSSPoint
FrameMetrics::ApplyRelativeScrollUpdateFrom(
165 const ScrollPositionUpdate
& aUpdate
) {
166 MOZ_ASSERT(aUpdate
.GetType() == ScrollUpdateType::Relative
);
167 CSSPoint origin
= GetVisualScrollOffset();
168 CSSPoint delta
= (aUpdate
.GetDestination() - aUpdate
.GetSource());
169 SetVisualScrollOffset(origin
+ delta
);
170 return GetVisualScrollOffset() - origin
;
173 CSSPoint
FrameMetrics::ApplyPureRelativeScrollUpdateFrom(
174 const ScrollPositionUpdate
& aUpdate
) {
175 MOZ_ASSERT(aUpdate
.GetType() == ScrollUpdateType::PureRelative
);
176 CSSPoint origin
= GetVisualScrollOffset();
177 ClampAndSetVisualScrollOffset(origin
+ aUpdate
.GetDelta());
178 return GetVisualScrollOffset() - origin
;
181 void FrameMetrics::UpdatePendingScrollInfo(const ScrollPositionUpdate
& aInfo
) {
182 // We only get this "pending scroll info" for paint-skip transactions,
183 // but PureRelative position updates always trigger a full paint, so
184 // we should never enter this code with a PureRelative update type. For
185 // the other types, the destination field on the ScrollPositionUpdate will
186 // tell us the final layout scroll position on the main thread.
187 MOZ_ASSERT(aInfo
.GetType() != ScrollUpdateType::PureRelative
);
189 // In applying a main-thread scroll update, try to preserve the relative
190 // offset between the visual and layout viewports.
191 CSSPoint relativeOffset
= GetVisualScrollOffset() - GetLayoutScrollOffset();
192 MOZ_ASSERT(IsRootContent() || relativeOffset
== CSSPoint());
194 SetLayoutScrollOffset(aInfo
.GetDestination());
195 ClampAndSetVisualScrollOffset(aInfo
.GetDestination() + relativeOffset
);
196 mScrollGeneration
= aInfo
.GetGeneration();
199 std::ostream
& operator<<(std::ostream
& aStream
,
200 const OverscrollBehavior
& aBehavior
) {
202 case OverscrollBehavior::Auto
: {
206 case OverscrollBehavior::Contain
: {
207 aStream
<< "contain";
210 case OverscrollBehavior::None
: {
218 OverscrollBehaviorInfo::OverscrollBehaviorInfo()
219 : mBehaviorX(OverscrollBehavior::Auto
),
220 mBehaviorY(OverscrollBehavior::Auto
) {}
222 static OverscrollBehavior
ToOverscrollBehavior(
223 StyleOverscrollBehavior aBehavior
) {
225 case StyleOverscrollBehavior::Auto
:
226 return OverscrollBehavior::Auto
;
227 case StyleOverscrollBehavior::Contain
:
228 return OverscrollBehavior::Contain
;
229 case StyleOverscrollBehavior::None
:
230 return OverscrollBehavior::None
;
232 MOZ_ASSERT_UNREACHABLE("Invalid overscroll behavior");
233 return OverscrollBehavior::Auto
;
236 OverscrollBehaviorInfo
OverscrollBehaviorInfo::FromStyleConstants(
237 StyleOverscrollBehavior aBehaviorX
, StyleOverscrollBehavior aBehaviorY
) {
238 OverscrollBehaviorInfo result
;
239 result
.mBehaviorX
= ToOverscrollBehavior(aBehaviorX
);
240 result
.mBehaviorY
= ToOverscrollBehavior(aBehaviorY
);
244 bool OverscrollBehaviorInfo::operator==(
245 const OverscrollBehaviorInfo
& aOther
) const {
246 return mBehaviorX
== aOther
.mBehaviorX
&& mBehaviorY
== aOther
.mBehaviorY
;
249 std::ostream
& operator<<(std::ostream
& aStream
,
250 const OverscrollBehaviorInfo
& aInfo
) {
251 if (aInfo
.mBehaviorX
== aInfo
.mBehaviorY
) {
252 aStream
<< aInfo
.mBehaviorX
;
254 aStream
<< "{ x=" << aInfo
.mBehaviorX
<< ", y=" << aInfo
.mBehaviorY
<< " }";
259 std::ostream
& operator<<(std::ostream
& aStream
,
260 const ScrollMetadata
& aMetadata
) {
261 aStream
<< "{ [description=" << aMetadata
.GetContentDescription()
262 << "] [metrics=" << aMetadata
.GetMetrics();
263 if (aMetadata
.GetScrollParentId() != ScrollableLayerGuid::NULL_SCROLL_ID
) {
264 aStream
<< "] [scrollParent=" << aMetadata
.GetScrollParentId();
266 if (aMetadata
.GetHasScrollgrab()) {
267 aStream
<< "] [scrollgrab";
269 aStream
<< "] [overscroll=" << aMetadata
.GetOverscrollBehavior() << "] ["
270 << aMetadata
.GetScrollUpdates().Length() << " scrollupdates"
275 StaticAutoPtr
<const ScrollMetadata
> ScrollMetadata::sNullMetadata
;
277 } // namespace layers
278 } // namespace mozilla