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