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 #include "Axis.h"
8
9 #include <math.h> // for fabsf, pow, powf
10 #include <algorithm> // for max
11
12 #include "APZCTreeManager.h" // for APZCTreeManager
13 #include "AsyncPanZoomController.h" // for AsyncPanZoomController
14 #include "FrameMetrics.h" // for FrameMetrics
15 #include "SimpleVelocityTracker.h" // for FrameMetrics
16 #include "mozilla/Attributes.h" // for final
17 #include "mozilla/Preferences.h" // for Preferences
18 #include "mozilla/gfx/Rect.h" // for RoundedIn
19 #include "mozilla/layers/APZThreadUtils.h" // for AssertOnControllerThread
20 #include "mozilla/mozalloc.h" // for operator new
21 #include "mozilla/FloatingPoint.h" // for FuzzyEqualsAdditive
22 #include "nsMathUtils.h" // for NS_lround
23 #include "nsPrintfCString.h" // for nsPrintfCString
24 #include "nsThreadUtils.h" // for NS_DispatchToMainThread, etc
25 #include "nscore.h" // for NS_IMETHOD
26
27 static mozilla::LazyLogModule sApzAxsLog("apz.axis");
28 #define AXIS_LOG(...) MOZ_LOG(sApzAxsLog, LogLevel::Debug, (__VA_ARGS__))
29
30 namespace mozilla {
31 namespace layers {
32
FuzzyEqualsCoordinate(float aValue1,float aValue2)33 bool FuzzyEqualsCoordinate(float aValue1, float aValue2) {
34 return FuzzyEqualsAdditive(aValue1, aValue2, COORDINATE_EPSILON) ||
35 FuzzyEqualsMultiplicative(aValue1, aValue2);
36 }
37
Axis(AsyncPanZoomController * aAsyncPanZoomController)38 Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
39 : mPos(0),
40 mVelocity(0.0f, "Axis::mVelocity"),
41 mAxisLocked(false),
42 mAsyncPanZoomController(aAsyncPanZoomController),
43 mOverscroll(0),
44 mMSDModel(0.0, 0.0, 0.0, StaticPrefs::apz_overscroll_spring_stiffness(),
45 StaticPrefs::apz_overscroll_damping()),
46 mVelocityTracker(mAsyncPanZoomController->GetPlatformSpecificState()
47 ->CreateVelocityTracker(this)) {}
48
ToLocalVelocity(float aVelocityInchesPerMs) const49 float Axis::ToLocalVelocity(float aVelocityInchesPerMs) const {
50 ScreenPoint velocity =
51 MakePoint(aVelocityInchesPerMs * mAsyncPanZoomController->GetDPI());
52 // Use ToScreenCoordinates() to convert a point rather than a vector by
53 // treating the point as a vector, and using (0, 0) as the anchor.
54 ScreenPoint panStart = mAsyncPanZoomController->ToScreenCoordinates(
55 mAsyncPanZoomController->PanStart(), ParentLayerPoint());
56 ParentLayerPoint localVelocity =
57 mAsyncPanZoomController->ToParentLayerCoordinates(velocity, panStart);
58 return localVelocity.Length();
59 }
60
UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos,TimeStamp aTimestamp)61 void Axis::UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos,
62 TimeStamp aTimestamp) {
63 // mVelocityTracker is controller-thread only
64 APZThreadUtils::AssertOnControllerThread();
65
66 mPos = aPos;
67
68 AXIS_LOG("%p|%s got position %f\n", mAsyncPanZoomController, Name(),
69 mPos.value);
70 if (Maybe<float> newVelocity =
71 mVelocityTracker->AddPosition(aPos, aTimestamp)) {
72 DoSetVelocity(mAxisLocked ? 0 : *newVelocity);
73 AXIS_LOG("%p|%s velocity from tracker is %f%s\n", mAsyncPanZoomController,
74 Name(), *newVelocity,
75 mAxisLocked ? ", but we are axis locked" : "");
76 }
77 }
78
StartTouch(ParentLayerCoord aPos,TimeStamp aTimestamp)79 void Axis::StartTouch(ParentLayerCoord aPos, TimeStamp aTimestamp) {
80 mStartPos = aPos;
81 mPos = aPos;
82 mVelocityTracker->StartTracking(aPos, aTimestamp);
83 mAxisLocked = false;
84 }
85
AdjustDisplacement(ParentLayerCoord aDisplacement,float & aDisplacementOut,float & aOverscrollAmountOut,bool aForceOverscroll)86 bool Axis::AdjustDisplacement(
87 ParentLayerCoord aDisplacement,
88 /* ParentLayerCoord */ float& aDisplacementOut,
89 /* ParentLayerCoord */ float& aOverscrollAmountOut,
90 bool aForceOverscroll /* = false */) {
91 if (mAxisLocked) {
92 aOverscrollAmountOut = 0;
93 aDisplacementOut = 0;
94 return false;
95 }
96 if (aForceOverscroll) {
97 aOverscrollAmountOut = aDisplacement;
98 aDisplacementOut = 0;
99 return false;
100 }
101
102 ParentLayerCoord displacement = aDisplacement;
103
104 // First consume any overscroll in the opposite direction along this axis.
105 ParentLayerCoord consumedOverscroll = 0;
106 if (mOverscroll > 0 && aDisplacement < 0) {
107 consumedOverscroll = std::min(mOverscroll, -aDisplacement);
108 } else if (mOverscroll < 0 && aDisplacement > 0) {
109 consumedOverscroll = 0.f - std::min(-mOverscroll, aDisplacement);
110 }
111 mOverscroll -= consumedOverscroll;
112 displacement += consumedOverscroll;
113
114 if (consumedOverscroll != 0.0f) {
115 AXIS_LOG("%p|%s changed overscroll amount to %f\n", mAsyncPanZoomController,
116 Name(), mOverscroll.value);
117 }
118
119 // Split the requested displacement into an allowed displacement that does
120 // not overscroll, and an overscroll amount.
121 aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement);
122 if (aOverscrollAmountOut != 0.0f) {
123 // No need to have a velocity along this axis anymore; it won't take us
124 // anywhere, so we're just spinning needlessly.
125 AXIS_LOG("%p|%s has overscrolled, clearing velocity\n",
126 mAsyncPanZoomController, Name());
127 DoSetVelocity(0.0f);
128 displacement -= aOverscrollAmountOut;
129 }
130 aDisplacementOut = displacement;
131 return fabsf(consumedOverscroll) > EPSILON;
132 }
133
ApplyResistance(ParentLayerCoord aRequestedOverscroll) const134 ParentLayerCoord Axis::ApplyResistance(
135 ParentLayerCoord aRequestedOverscroll) const {
136 // 'resistanceFactor' is a value between 0 and 1/16, which:
137 // - tends to 1/16 as the existing overscroll tends to 0
138 // - tends to 0 as the existing overscroll tends to the composition length
139 // The actual overscroll is the requested overscroll multiplied by this
140 // factor.
141 float resistanceFactor =
142 (1 - fabsf(GetOverscroll()) / GetCompositionLength()) / 16;
143 float result = resistanceFactor < 0 ? ParentLayerCoord(0)
144 : aRequestedOverscroll * resistanceFactor;
145 result = clamped(result, -8.0f, 8.0f);
146 return result;
147 }
148
OverscrollBy(ParentLayerCoord aOverscroll)149 void Axis::OverscrollBy(ParentLayerCoord aOverscroll) {
150 MOZ_ASSERT(CanScroll());
151 // We can get some spurious calls to OverscrollBy() with near-zero values
152 // due to rounding error. Ignore those (they might trip the asserts below.)
153 if (FuzzyEqualsAdditive(aOverscroll.value, 0.0f, COORDINATE_EPSILON)) {
154 return;
155 }
156 EndOverscrollAnimation();
157 aOverscroll = ApplyResistance(aOverscroll);
158 if (aOverscroll > 0) {
159 #ifdef DEBUG
160 if (!IsScrolledToEnd()) {
161 nsPrintfCString message(
162 "composition end (%f) is not equal (within error) to page end (%f)\n",
163 GetCompositionEnd().value, GetPageEnd().value);
164 NS_ASSERTION(false, message.get());
165 MOZ_CRASH("GFX: Overscroll issue > 0");
166 }
167 #endif
168 MOZ_ASSERT(mOverscroll >= 0);
169 } else if (aOverscroll < 0) {
170 #ifdef DEBUG
171 if (!IsScrolledToStart()) {
172 nsPrintfCString message(
173 "composition origin (%f) is not equal (within error) to page origin "
174 "(%f)\n",
175 GetOrigin().value, GetPageStart().value);
176 NS_ASSERTION(false, message.get());
177 MOZ_CRASH("GFX: Overscroll issue < 0");
178 }
179 #endif
180 MOZ_ASSERT(mOverscroll <= 0);
181 }
182 mOverscroll += aOverscroll;
183
184 AXIS_LOG("%p|%s changed overscroll amount to %f\n", mAsyncPanZoomController,
185 Name(), mOverscroll.value);
186 }
187
GetOverscroll() const188 ParentLayerCoord Axis::GetOverscroll() const { return mOverscroll; }
189
RestoreOverscroll(ParentLayerCoord aOverscroll)190 void Axis::RestoreOverscroll(ParentLayerCoord aOverscroll) {
191 mOverscroll = aOverscroll;
192 }
193
StartOverscrollAnimation(float aVelocity)194 void Axis::StartOverscrollAnimation(float aVelocity) {
195 const float maxVelocity = StaticPrefs::apz_overscroll_max_velocity();
196 aVelocity = clamped(aVelocity / 2.0f, -maxVelocity, maxVelocity);
197 SetVelocity(aVelocity);
198 mMSDModel.SetPosition(mOverscroll);
199 // Convert velocity from ParentLayerCoords/millisecond to
200 // ParentLayerCoords/second.
201 mMSDModel.SetVelocity(DoGetVelocity() * 1000.0);
202
203 AXIS_LOG(
204 "%p|%s beginning overscroll animation with amount %f and velocity %f\n",
205 mAsyncPanZoomController, Name(), mOverscroll.value, DoGetVelocity());
206 }
207
EndOverscrollAnimation()208 void Axis::EndOverscrollAnimation() {
209 mMSDModel.SetPosition(0.0);
210 mMSDModel.SetVelocity(0.0);
211 }
212
SampleOverscrollAnimation(const TimeDuration & aDelta)213 bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta) {
214 mMSDModel.Simulate(aDelta);
215 mOverscroll = mMSDModel.GetPosition();
216
217 AXIS_LOG("%p|%s changed overscroll amount to %f\n", mAsyncPanZoomController,
218 Name(), mOverscroll.value);
219
220 if (mMSDModel.IsFinished(1.0)) {
221 // "Jump" to the at-rest state. The jump shouldn't be noticeable as the
222 // velocity and overscroll are already low.
223 AXIS_LOG("%p|%s oscillation dropped below threshold, going to rest\n",
224 mAsyncPanZoomController, Name());
225 ClearOverscroll();
226 DoSetVelocity(0);
227 return false;
228 }
229
230 // Otherwise, continue the animation.
231 return true;
232 }
233
IsOverscrollAnimationRunning() const234 bool Axis::IsOverscrollAnimationRunning() const {
235 return !mMSDModel.IsFinished(1.0);
236 }
237
IsOverscrollAnimationAlive() const238 bool Axis::IsOverscrollAnimationAlive() const {
239 // Unlike IsOverscrollAnimationRunning, check the position and the velocity to
240 // be sure that the animation has started but hasn't yet finished.
241 return mMSDModel.GetPosition() != 0.0 || mMSDModel.GetVelocity() != 0.0;
242 }
243
IsOverscrolled() const244 bool Axis::IsOverscrolled() const { return mOverscroll != 0.f; }
245
IsScrolledToStart() const246 bool Axis::IsScrolledToStart() const {
247 return FuzzyEqualsCoordinate(GetOrigin().value, GetPageStart().value);
248 }
249
IsScrolledToEnd() const250 bool Axis::IsScrolledToEnd() const {
251 return FuzzyEqualsCoordinate(GetCompositionEnd().value, GetPageEnd().value);
252 }
253
IsInInvalidOverscroll() const254 bool Axis::IsInInvalidOverscroll() const {
255 if (mOverscroll > 0) {
256 return !IsScrolledToEnd();
257 } else if (mOverscroll < 0) {
258 return !IsScrolledToStart();
259 }
260 return false;
261 }
262
ClearOverscroll()263 void Axis::ClearOverscroll() {
264 EndOverscrollAnimation();
265 mOverscroll = 0;
266 }
267
PanStart() const268 ParentLayerCoord Axis::PanStart() const { return mStartPos; }
269
PanDistance() const270 ParentLayerCoord Axis::PanDistance() const { return fabs(mPos - mStartPos); }
271
PanDistance(ParentLayerCoord aPos) const272 ParentLayerCoord Axis::PanDistance(ParentLayerCoord aPos) const {
273 return fabs(aPos - mStartPos);
274 }
275
EndTouch(TimeStamp aTimestamp)276 void Axis::EndTouch(TimeStamp aTimestamp) {
277 // mVelocityQueue is controller-thread only
278 APZThreadUtils::AssertOnControllerThread();
279
280 // If the velocity tracker wasn't able to compute a velocity, zero out
281 // the velocity to make sure we don't get a fling based on some old and
282 // no-longer-relevant value of mVelocity. Also if the axis is locked then
283 // just reset the velocity to 0 since we don't need any velocity to carry
284 // into the fling.
285 if (mAxisLocked) {
286 DoSetVelocity(0);
287 } else if (Maybe<float> velocity =
288 mVelocityTracker->ComputeVelocity(aTimestamp)) {
289 DoSetVelocity(*velocity);
290 } else {
291 DoSetVelocity(0);
292 }
293 mAxisLocked = false;
294 AXIS_LOG("%p|%s ending touch, computed velocity %f\n",
295 mAsyncPanZoomController, Name(), DoGetVelocity());
296 }
297
CancelGesture()298 void Axis::CancelGesture() {
299 // mVelocityQueue is controller-thread only
300 APZThreadUtils::AssertOnControllerThread();
301
302 AXIS_LOG("%p|%s cancelling touch, clearing velocity queue\n",
303 mAsyncPanZoomController, Name());
304 DoSetVelocity(0.0f);
305 mVelocityTracker->Clear();
306 }
307
CanScroll() const308 bool Axis::CanScroll() const {
309 return GetPageLength() - GetCompositionLength() > COORDINATE_EPSILON;
310 }
311
CanScroll(ParentLayerCoord aDelta) const312 bool Axis::CanScroll(ParentLayerCoord aDelta) const {
313 if (!CanScroll() || mAxisLocked) {
314 return false;
315 }
316
317 return fabs(DisplacementWillOverscrollAmount(aDelta) - aDelta) >
318 COORDINATE_EPSILON;
319 }
320
ClampOriginToScrollableRect(CSSCoord aOrigin) const321 CSSCoord Axis::ClampOriginToScrollableRect(CSSCoord aOrigin) const {
322 CSSToParentLayerScale zoom = GetAxisScale(GetFrameMetrics().GetZoom());
323 ParentLayerCoord origin = aOrigin * zoom;
324 ParentLayerCoord result;
325 if (origin < GetPageStart()) {
326 result = GetPageStart();
327 } else if (origin + GetCompositionLength() > GetPageEnd()) {
328 result = GetPageEnd() - GetCompositionLength();
329 } else {
330 return aOrigin;
331 }
332 if (zoom == CSSToParentLayerScale(0)) {
333 return aOrigin;
334 }
335 return result / zoom;
336 }
337
CanScrollNow() const338 bool Axis::CanScrollNow() const { return !mAxisLocked && CanScroll(); }
339
DisplacementWillOverscrollAmount(ParentLayerCoord aDisplacement) const340 ParentLayerCoord Axis::DisplacementWillOverscrollAmount(
341 ParentLayerCoord aDisplacement) const {
342 ParentLayerCoord newOrigin = GetOrigin() + aDisplacement;
343 ParentLayerCoord newCompositionEnd = GetCompositionEnd() + aDisplacement;
344 // If the current pan plus a displacement takes the window to the left of or
345 // above the current page rect.
346 bool minus = newOrigin < GetPageStart();
347 // If the current pan plus a displacement takes the window to the right of or
348 // below the current page rect.
349 bool plus = newCompositionEnd > GetPageEnd();
350 if (minus && plus) {
351 // Don't handle overscrolled in both directions; a displacement can't cause
352 // this, it must have already been zoomed out too far.
353 return 0;
354 }
355 if (minus) {
356 return newOrigin - GetPageStart();
357 }
358 if (plus) {
359 return newCompositionEnd - GetPageEnd();
360 }
361 return 0;
362 }
363
ScaleWillOverscrollAmount(float aScale,CSSCoord aFocus) const364 CSSCoord Axis::ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const {
365 // Internally, do computations in ParentLayer coordinates *before* the scale
366 // is applied.
367 CSSToParentLayerScale zoom = GetAxisScale(GetFrameMetrics().GetZoom());
368 ParentLayerCoord focus = aFocus * zoom;
369 ParentLayerCoord originAfterScale = (GetOrigin() + focus) - (focus / aScale);
370
371 bool both = ScaleWillOverscrollBothSides(aScale);
372 bool minus = GetPageStart() - originAfterScale > COORDINATE_EPSILON;
373 bool plus =
374 (originAfterScale + (GetCompositionLength() / aScale)) - GetPageEnd() >
375 COORDINATE_EPSILON;
376
377 if ((minus && plus) || both) {
378 // If we ever reach here it's a bug in the client code.
379 MOZ_ASSERT(false,
380 "In an OVERSCROLL_BOTH condition in ScaleWillOverscrollAmount");
381 return 0;
382 }
383 if (minus && zoom != CSSToParentLayerScale(0)) {
384 return (originAfterScale - GetPageStart()) / zoom;
385 }
386 if (plus && zoom != CSSToParentLayerScale(0)) {
387 return (originAfterScale + (GetCompositionLength() / aScale) -
388 GetPageEnd()) /
389 zoom;
390 }
391 return 0;
392 }
393
IsAxisLocked() const394 bool Axis::IsAxisLocked() const { return mAxisLocked; }
395
GetVelocity() const396 float Axis::GetVelocity() const { return mAxisLocked ? 0 : DoGetVelocity(); }
397
SetVelocity(float aVelocity)398 void Axis::SetVelocity(float aVelocity) {
399 AXIS_LOG("%p|%s direct-setting velocity to %f\n", mAsyncPanZoomController,
400 Name(), aVelocity);
401 DoSetVelocity(aVelocity);
402 }
403
GetCompositionEnd() const404 ParentLayerCoord Axis::GetCompositionEnd() const {
405 return GetOrigin() + GetCompositionLength();
406 }
407
GetPageEnd() const408 ParentLayerCoord Axis::GetPageEnd() const {
409 return GetPageStart() + GetPageLength();
410 }
411
GetScrollRangeEnd() const412 ParentLayerCoord Axis::GetScrollRangeEnd() const {
413 return GetPageEnd() - GetCompositionLength();
414 }
415
GetOrigin() const416 ParentLayerCoord Axis::GetOrigin() const {
417 ParentLayerPoint origin =
418 GetFrameMetrics().GetVisualScrollOffset() * GetFrameMetrics().GetZoom();
419 return GetPointOffset(origin);
420 }
421
GetCompositionLength() const422 ParentLayerCoord Axis::GetCompositionLength() const {
423 return GetRectLength(GetFrameMetrics().GetCompositionBounds());
424 }
425
GetPageStart() const426 ParentLayerCoord Axis::GetPageStart() const {
427 ParentLayerRect pageRect = GetFrameMetrics().GetExpandedScrollableRect() *
428 GetFrameMetrics().GetZoom();
429 return GetRectOffset(pageRect);
430 }
431
GetPageLength() const432 ParentLayerCoord Axis::GetPageLength() const {
433 ParentLayerRect pageRect = GetFrameMetrics().GetExpandedScrollableRect() *
434 GetFrameMetrics().GetZoom();
435 return GetRectLength(pageRect);
436 }
437
ScaleWillOverscrollBothSides(float aScale) const438 bool Axis::ScaleWillOverscrollBothSides(float aScale) const {
439 const FrameMetrics& metrics = GetFrameMetrics();
440 ParentLayerRect screenCompositionBounds =
441 metrics.GetCompositionBounds() / ParentLayerToParentLayerScale(aScale);
442 return GetRectLength(screenCompositionBounds) - GetPageLength() >
443 COORDINATE_EPSILON;
444 }
445
DoGetVelocity() const446 float Axis::DoGetVelocity() const {
447 auto velocity = mVelocity.Lock();
448 return velocity.ref();
449 }
DoSetVelocity(float aVelocity)450 void Axis::DoSetVelocity(float aVelocity) {
451 auto velocity = mVelocity.Lock();
452 velocity.ref() = aVelocity;
453 }
454
GetFrameMetrics() const455 const FrameMetrics& Axis::GetFrameMetrics() const {
456 return mAsyncPanZoomController->GetFrameMetrics();
457 }
458
GetScrollMetadata() const459 const ScrollMetadata& Axis::GetScrollMetadata() const {
460 return mAsyncPanZoomController->GetScrollMetadata();
461 }
462
OverscrollBehaviorAllowsHandoff() const463 bool Axis::OverscrollBehaviorAllowsHandoff() const {
464 // Scroll handoff is a "non-local" overscroll behavior, so it's allowed
465 // with "auto" and disallowed with "contain" and "none".
466 return GetOverscrollBehavior() == OverscrollBehavior::Auto;
467 }
468
OverscrollBehaviorAllowsOverscrollEffect() const469 bool Axis::OverscrollBehaviorAllowsOverscrollEffect() const {
470 // An overscroll effect is a "local" overscroll behavior, so it's allowed
471 // with "auto" and "contain" and disallowed with "none".
472 return GetOverscrollBehavior() != OverscrollBehavior::None;
473 }
474
AxisX(AsyncPanZoomController * aAsyncPanZoomController)475 AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
476 : Axis(aAsyncPanZoomController) {}
477
GetPointOffset(const CSSPoint & aPoint) const478 CSSCoord AxisX::GetPointOffset(const CSSPoint& aPoint) const {
479 return aPoint.x;
480 }
481
GetPointOffset(const ParentLayerPoint & aPoint) const482 ParentLayerCoord AxisX::GetPointOffset(const ParentLayerPoint& aPoint) const {
483 return aPoint.x;
484 }
485
GetAxisScale(const CSSToParentLayerScale2D & aScale) const486 CSSToParentLayerScale AxisX::GetAxisScale(
487 const CSSToParentLayerScale2D& aScale) const {
488 return CSSToParentLayerScale(aScale.xScale);
489 }
490
GetRectLength(const ParentLayerRect & aRect) const491 ParentLayerCoord AxisX::GetRectLength(const ParentLayerRect& aRect) const {
492 return aRect.Width();
493 }
494
GetRectOffset(const ParentLayerRect & aRect) const495 ParentLayerCoord AxisX::GetRectOffset(const ParentLayerRect& aRect) const {
496 return aRect.X();
497 }
498
GetTransformScale(const AsyncTransformComponentMatrix & aMatrix) const499 float AxisX::GetTransformScale(
500 const AsyncTransformComponentMatrix& aMatrix) const {
501 return aMatrix._11;
502 }
503
GetTransformTranslation(const AsyncTransformComponentMatrix & aMatrix) const504 ParentLayerCoord AxisX::GetTransformTranslation(
505 const AsyncTransformComponentMatrix& aMatrix) const {
506 return aMatrix._41;
507 }
508
PostScale(AsyncTransformComponentMatrix & aMatrix,float aScale) const509 void AxisX::PostScale(AsyncTransformComponentMatrix& aMatrix,
510 float aScale) const {
511 aMatrix.PostScale(aScale, 1.f, 1.f);
512 }
513
PostTranslate(AsyncTransformComponentMatrix & aMatrix,ParentLayerCoord aTranslation) const514 void AxisX::PostTranslate(AsyncTransformComponentMatrix& aMatrix,
515 ParentLayerCoord aTranslation) const {
516 aMatrix.PostTranslate(aTranslation, 0, 0);
517 }
518
MakePoint(ScreenCoord aCoord) const519 ScreenPoint AxisX::MakePoint(ScreenCoord aCoord) const {
520 return ScreenPoint(aCoord, 0);
521 }
522
Name() const523 const char* AxisX::Name() const { return "X"; }
524
CanScrollTo(Side aSide) const525 bool AxisX::CanScrollTo(Side aSide) const {
526 switch (aSide) {
527 case eSideLeft:
528 return CanScroll(-COORDINATE_EPSILON * 2);
529 case eSideRight:
530 return CanScroll(COORDINATE_EPSILON * 2);
531 default:
532 MOZ_ASSERT_UNREACHABLE("aSide is out of valid values");
533 return false;
534 }
535 }
536
ScrollableDirections() const537 SideBits AxisX::ScrollableDirections() const {
538 SideBits directions = SideBits::eNone;
539
540 if (CanScrollTo(eSideLeft)) {
541 directions |= SideBits::eLeft;
542 }
543 if (CanScrollTo(eSideRight)) {
544 directions |= SideBits::eRight;
545 }
546
547 return directions;
548 }
549
GetOverscrollBehavior() const550 OverscrollBehavior AxisX::GetOverscrollBehavior() const {
551 return GetScrollMetadata().GetOverscrollBehavior().mBehaviorX;
552 }
553
AxisY(AsyncPanZoomController * aAsyncPanZoomController)554 AxisY::AxisY(AsyncPanZoomController* aAsyncPanZoomController)
555 : Axis(aAsyncPanZoomController) {}
556
GetPointOffset(const CSSPoint & aPoint) const557 CSSCoord AxisY::GetPointOffset(const CSSPoint& aPoint) const {
558 return aPoint.y;
559 }
560
GetPointOffset(const ParentLayerPoint & aPoint) const561 ParentLayerCoord AxisY::GetPointOffset(const ParentLayerPoint& aPoint) const {
562 return aPoint.y;
563 }
564
GetAxisScale(const CSSToParentLayerScale2D & aScale) const565 CSSToParentLayerScale AxisY::GetAxisScale(
566 const CSSToParentLayerScale2D& aScale) const {
567 return CSSToParentLayerScale(aScale.yScale);
568 }
569
GetRectLength(const ParentLayerRect & aRect) const570 ParentLayerCoord AxisY::GetRectLength(const ParentLayerRect& aRect) const {
571 return aRect.Height();
572 }
573
GetRectOffset(const ParentLayerRect & aRect) const574 ParentLayerCoord AxisY::GetRectOffset(const ParentLayerRect& aRect) const {
575 return aRect.Y();
576 }
577
GetTransformScale(const AsyncTransformComponentMatrix & aMatrix) const578 float AxisY::GetTransformScale(
579 const AsyncTransformComponentMatrix& aMatrix) const {
580 return aMatrix._22;
581 }
582
GetTransformTranslation(const AsyncTransformComponentMatrix & aMatrix) const583 ParentLayerCoord AxisY::GetTransformTranslation(
584 const AsyncTransformComponentMatrix& aMatrix) const {
585 return aMatrix._42;
586 }
587
PostScale(AsyncTransformComponentMatrix & aMatrix,float aScale) const588 void AxisY::PostScale(AsyncTransformComponentMatrix& aMatrix,
589 float aScale) const {
590 aMatrix.PostScale(1.f, aScale, 1.f);
591 }
592
PostTranslate(AsyncTransformComponentMatrix & aMatrix,ParentLayerCoord aTranslation) const593 void AxisY::PostTranslate(AsyncTransformComponentMatrix& aMatrix,
594 ParentLayerCoord aTranslation) const {
595 aMatrix.PostTranslate(0, aTranslation, 0);
596 }
597
MakePoint(ScreenCoord aCoord) const598 ScreenPoint AxisY::MakePoint(ScreenCoord aCoord) const {
599 return ScreenPoint(0, aCoord);
600 }
601
Name() const602 const char* AxisY::Name() const { return "Y"; }
603
CanScrollTo(Side aSide) const604 bool AxisY::CanScrollTo(Side aSide) const {
605 switch (aSide) {
606 case eSideTop:
607 return CanScroll(-COORDINATE_EPSILON * 2);
608 case eSideBottom:
609 return CanScroll(COORDINATE_EPSILON * 2);
610 default:
611 MOZ_ASSERT_UNREACHABLE("aSide is out of valid values");
612 return false;
613 }
614 }
615
ScrollableDirections() const616 SideBits AxisY::ScrollableDirections() const {
617 SideBits directions = SideBits::eNone;
618
619 if (CanScrollTo(eSideTop)) {
620 directions |= SideBits::eTop;
621 }
622 if (CanScrollTo(eSideBottom)) {
623 directions |= SideBits::eBottom;
624 }
625
626 return directions;
627 }
628
HasDynamicToolbar() const629 bool AxisY::HasDynamicToolbar() const {
630 return GetCompositionLengthWithoutDynamicToolbar() != ParentLayerCoord(0);
631 }
632
ScrollableDirectionsWithDynamicToolbar(const ScreenMargin & aFixedLayerMargins) const633 SideBits AxisY::ScrollableDirectionsWithDynamicToolbar(
634 const ScreenMargin& aFixedLayerMargins) const {
635 MOZ_ASSERT(mAsyncPanZoomController->IsRootContent());
636
637 SideBits directions = ScrollableDirections();
638
639 if (HasDynamicToolbar()) {
640 ScreenCoord toolbarHeight = ViewAs<ScreenPixel>(
641 GetCompositionLength() - GetCompositionLengthWithoutDynamicToolbar(),
642 PixelCastJustification::ScreenIsParentLayerForRoot);
643
644 if (fabs(aFixedLayerMargins.bottom) > COORDINATE_EPSILON) {
645 directions |= SideBits::eTop;
646 }
647 if (toolbarHeight + aFixedLayerMargins.bottom > COORDINATE_EPSILON) {
648 directions |= SideBits::eBottom;
649 }
650 }
651
652 return directions;
653 }
654
CanVerticalScrollWithDynamicToolbar() const655 bool AxisY::CanVerticalScrollWithDynamicToolbar() const {
656 return !HasDynamicToolbar()
657 ? CanScroll()
658 : GetPageLength() - GetCompositionLengthWithoutDynamicToolbar() >
659 COORDINATE_EPSILON;
660 }
661
GetOverscrollBehavior() const662 OverscrollBehavior AxisY::GetOverscrollBehavior() const {
663 return GetScrollMetadata().GetOverscrollBehavior().mBehaviorY;
664 }
665
GetCompositionLengthWithoutDynamicToolbar() const666 ParentLayerCoord AxisY::GetCompositionLengthWithoutDynamicToolbar() const {
667 return GetFrameMetrics().GetCompositionSizeWithoutDynamicToolbar().Height();
668 }
669
670 } // namespace layers
671 } // namespace mozilla
672