tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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