tor-browser

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

TestSnapping.cpp (12758B)


      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 "APZCTreeManagerTester.h"
      8 #include "APZTestCommon.h"
      9 
     10 #include "InputUtils.h"
     11 #include "mozilla/StaticPrefs_layout.h"
     12 #include "mozilla/StaticPrefs_mousewheel.h"
     13 
     14 class APZCSnappingTesterMock : public APZCTreeManagerTester {
     15 public:
     16  APZCSnappingTesterMock() { CreateMockHitTester(); }
     17 };
     18 
     19 TEST_F(APZCSnappingTesterMock, Bug1265510) {
     20  // Needed because the test uses SmoothWheel()
     21  SCOPED_GFX_PREF_BOOL("general.smoothScroll", true);
     22 
     23  const char* treeShape = "x(x)";
     24  LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100),
     25                                     LayerIntRect(0, 100, 100, 100)};
     26  CreateScrollData(treeShape, layerVisibleRect);
     27  SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
     28                            CSSRect(0, 0, 100, 200));
     29  SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1,
     30                            CSSRect(0, 0, 100, 200));
     31  SetScrollHandoff(layers[1], root);
     32 
     33  ScrollSnapInfo snap;
     34  snap.mScrollSnapStrictnessY = StyleScrollSnapStrictness::Mandatory;
     35  snap.mSnapportSize =
     36      CSSSize::ToAppUnits(layerVisibleRect[0].Size() * LayerToCSSScale(1.0));
     37 
     38  snap.mSnapTargets.AppendElement(ScrollSnapInfo::SnapTarget(
     39      Nothing(), Some(0 * AppUnitsPerCSSPixel()),
     40      CSSRect::ToAppUnits(CSSRect(0, 0, 10, 10)), StyleScrollSnapStop::Normal,
     41      ScrollSnapTargetId{1}));
     42  snap.mSnapTargets.AppendElement(ScrollSnapInfo::SnapTarget(
     43      Nothing(), Some(100 * AppUnitsPerCSSPixel()),
     44      CSSRect::ToAppUnits(CSSRect(0, 100, 10, 10)), StyleScrollSnapStop::Normal,
     45      ScrollSnapTargetId{2}));
     46 
     47  ModifyFrameMetrics(root, [&](ScrollMetadata& aSm, FrameMetrics&) {
     48    aSm.SetSnapInfo(ScrollSnapInfo(snap));
     49  });
     50 
     51  UniquePtr<ScopedLayerTreeRegistration> registration =
     52      MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
     53  UpdateHitTestingTree();
     54 
     55  TestAsyncPanZoomController* outer = ApzcOf(layers[0]);
     56  TestAsyncPanZoomController* inner = ApzcOf(layers[1]);
     57 
     58  // Position the mouse near the bottom of the outer frame and scroll by 60px.
     59  // (6 lines of 10px each). APZC will actually scroll to y=100 because of the
     60  // mandatory snap coordinate there.
     61  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
     62  SmoothWheel(manager, ScreenIntPoint(50, 80), ScreenPoint(0, 6), mcc->Time());
     63  // Advance in 5ms increments until we've scrolled by 70px. At this point, the
     64  // closest snap point is y=100, and the inner frame should be under the mouse
     65  // cursor.
     66  while (outer
     67             ->GetCurrentAsyncScrollOffset(
     68                 AsyncTransformConsumer::eForEventHandling)
     69             .y < 70) {
     70    mcc->AdvanceByMillis(5);
     71    outer->AdvanceAnimations(mcc->GetSampleTime());
     72  }
     73  // Now do another wheel in a new transaction. This should start scrolling the
     74  // inner frame; we verify that it does by checking the inner scroll position.
     75  mcc->AdvanceBy(TimeDuration::FromMilliseconds(
     76      StaticPrefs::mousewheel_transaction_timeout() + 100));
     77  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
     78  SmoothWheel(manager, ScreenIntPoint(50, 80), ScreenPoint(0, 6), mcc->Time());
     79  mcc->AdvanceByMillis(5);
     80  inner->AdvanceAnimationsUntilEnd();
     81  EXPECT_LT(0.0f, inner
     82                      ->GetCurrentAsyncScrollOffset(
     83                          AsyncTransformConsumer::eForEventHandling)
     84                      .y);
     85 
     86  // However, the outer frame should also continue to the snap point, otherwise
     87  // it is demonstrating incorrect behaviour by violating the mandatory
     88  // snapping.
     89  outer->AdvanceAnimationsUntilEnd();
     90  EXPECT_EQ(100.0f, outer
     91                        ->GetCurrentAsyncScrollOffset(
     92                            AsyncTransformConsumer::eForEventHandling)
     93                        .y);
     94 }
     95 
     96 TEST_F(APZCSnappingTesterMock, Snap_After_Pinch) {
     97  const char* treeShape = "x";
     98  LayerIntRect layerVisibleRect[] = {
     99      LayerIntRect(0, 0, 100, 100),
    100  };
    101  CreateScrollData(treeShape, layerVisibleRect);
    102  SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
    103                            CSSRect(0, 0, 100, 200));
    104 
    105  // Set up some basic scroll snapping
    106  ScrollSnapInfo snap;
    107  snap.mScrollSnapStrictnessY = StyleScrollSnapStrictness::Mandatory;
    108  snap.mSnapportSize =
    109      CSSSize::ToAppUnits(layerVisibleRect[0].Size() * LayerToCSSScale(1.0));
    110 
    111  snap.mSnapTargets.AppendElement(ScrollSnapInfo::SnapTarget(
    112      Nothing(), Some(0 * AppUnitsPerCSSPixel()),
    113      CSSRect::ToAppUnits(CSSRect(0, 0, 10, 10)), StyleScrollSnapStop::Normal,
    114      ScrollSnapTargetId{1}));
    115  snap.mSnapTargets.AppendElement(ScrollSnapInfo::SnapTarget(
    116      Nothing(), Some(100 * AppUnitsPerCSSPixel()),
    117      CSSRect::ToAppUnits(CSSRect(0, 100, 10, 10)), StyleScrollSnapStop::Normal,
    118      ScrollSnapTargetId{2}));
    119 
    120  // Save the scroll snap info on the root APZC.
    121  // Also mark the root APZC as "root content", since APZC only allows
    122  // zooming on the root content APZC.
    123  ModifyFrameMetrics(root, [&](ScrollMetadata& aSm, FrameMetrics& aMetrics) {
    124    aSm.SetSnapInfo(ScrollSnapInfo(snap));
    125    aMetrics.SetIsRootContent(true);
    126  });
    127 
    128  UniquePtr<ScopedLayerTreeRegistration> registration =
    129      MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
    130  UpdateHitTestingTree();
    131 
    132  RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root);
    133 
    134  // Allow zooming
    135  apzc->UpdateZoomConstraints(ZoomConstraints(
    136      true, true, CSSToParentLayerScale(0.25f), CSSToParentLayerScale(4.0f)));
    137 
    138  PinchWithPinchInput(apzc, ScreenIntPoint(50, 50), ScreenIntPoint(50, 50),
    139                      1.2f);
    140 
    141  apzc->AssertInSmoothMsdScroll();
    142 }
    143 
    144 // Currently fails on Android because on the platform we have a different
    145 // VelocityTracker.
    146 #ifndef MOZ_WIDGET_ANDROID
    147 TEST_F(APZCSnappingTesterMock, SnapOnPanEndWithZeroVelocity) {
    148  // Use pref values for desktop everywhere.
    149  SCOPED_GFX_PREF_FLOAT("apz.fling_friction", 0.002);
    150  SCOPED_GFX_PREF_FLOAT("apz.fling_stopped_threshold", 0.01);
    151  SCOPED_GFX_PREF_FLOAT("apz.fling_curve_function_x1", 0.0);
    152  SCOPED_GFX_PREF_FLOAT("apz.fling_curve_function_x2", 1.0);
    153  SCOPED_GFX_PREF_FLOAT("apz.fling_curve_function_y1", 0.0);
    154  SCOPED_GFX_PREF_FLOAT("apz.fling_curve_function_y2", 1.0);
    155  SCOPED_GFX_PREF_INT("apz.velocity_relevance_time_ms", 100);
    156 
    157  const char* treeShape = "x";
    158  LayerIntRect layerVisibleRect[] = {
    159      LayerIntRect(0, 0, 100, 100),
    160  };
    161  CreateScrollData(treeShape, layerVisibleRect);
    162  SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
    163                            CSSRect(0, 0, 100, 400));
    164 
    165  // Set up two snap points, 30 and 100.
    166  ScrollSnapInfo snap;
    167  snap.mScrollSnapStrictnessY = StyleScrollSnapStrictness::Mandatory;
    168  snap.mSnapportSize =
    169      CSSSize::ToAppUnits(layerVisibleRect[0].Size() * LayerToCSSScale(1.0));
    170  snap.mSnapTargets.AppendElement(ScrollSnapInfo::SnapTarget(
    171      Nothing(), Some(30 * AppUnitsPerCSSPixel()),
    172      CSSRect::ToAppUnits(CSSRect(0, 30, 10, 10)), StyleScrollSnapStop::Normal,
    173      ScrollSnapTargetId{1}));
    174  snap.mSnapTargets.AppendElement(ScrollSnapInfo::SnapTarget(
    175      Nothing(), Some(100 * AppUnitsPerCSSPixel()),
    176      CSSRect::ToAppUnits(CSSRect(0, 100, 10, 10)), StyleScrollSnapStop::Normal,
    177      ScrollSnapTargetId{2}));
    178 
    179  // Save the scroll snap info on the root APZC.
    180  ModifyFrameMetrics(root, [&](ScrollMetadata& aSm, FrameMetrics& aMetrics) {
    181    aSm.SetSnapInfo(ScrollSnapInfo(snap));
    182  });
    183 
    184  UniquePtr<ScopedLayerTreeRegistration> registration =
    185      MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
    186  UpdateHitTestingTree();
    187 
    188  RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root);
    189 
    190  // Send a series of pan gestures to scroll to position at 50.
    191  const ScreenIntPoint position = ScreenIntPoint(50, 30);
    192  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
    193  PanGesture(PanGestureInput::PANGESTURE_START, manager, position,
    194             ScreenPoint(0, 10), mcc->Time());
    195  mcc->AdvanceByMillis(5);
    196  apzc->AdvanceAnimations(mcc->GetSampleTime());
    197  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
    198  PanGesture(PanGestureInput::PANGESTURE_PAN, manager, position,
    199             ScreenPoint(0, 40), mcc->Time());
    200  mcc->AdvanceByMillis(5);
    201  apzc->AdvanceAnimations(mcc->GetSampleTime());
    202 
    203  // Make sure the velocity just before sending a pan-end is zero.
    204  EXPECT_EQ(apzc->GetVelocityVector().y, 0);
    205 
    206  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
    207  PanGesture(PanGestureInput::PANGESTURE_END, manager, position,
    208             ScreenPoint(0, 0), mcc->Time());
    209 
    210  // Now a smooth animation has been triggered for snapping to 30.
    211  apzc->AssertInSmoothMsdScroll();
    212 
    213  apzc->AdvanceAnimationsUntilEnd();
    214  // The snapped position should be 30 rather than 100 because it's the nearest
    215  // snap point.
    216  EXPECT_EQ(apzc->GetCurrentAsyncScrollOffset(
    217                    AsyncPanZoomController::eForEventHandling)
    218                .y,
    219            30);
    220 }
    221 
    222 // Smililar to above SnapOnPanEndWithZeroVelocity but with positive velocity so
    223 // that the snap position would be the one in the scrolling direction.
    224 TEST_F(APZCSnappingTesterMock, SnapOnPanEndWithPositiveVelocity) {
    225  // Use pref values for desktop everywhere.
    226  SCOPED_GFX_PREF_FLOAT("apz.fling_friction", 0.002);
    227  SCOPED_GFX_PREF_FLOAT("apz.fling_stopped_threshold", 0.01);
    228  SCOPED_GFX_PREF_FLOAT("apz.fling_curve_function_x1", 0.0);
    229  SCOPED_GFX_PREF_FLOAT("apz.fling_curve_function_x2", 1.0);
    230  SCOPED_GFX_PREF_FLOAT("apz.fling_curve_function_y1", 0.0);
    231  SCOPED_GFX_PREF_FLOAT("apz.fling_curve_function_y2", 1.0);
    232  SCOPED_GFX_PREF_INT("apz.velocity_relevance_time_ms", 100);
    233 
    234  const char* treeShape = "x";
    235  LayerIntRect layerVisibleRect[] = {
    236      LayerIntRect(0, 0, 100, 100),
    237  };
    238  CreateScrollData(treeShape, layerVisibleRect);
    239  SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
    240                            CSSRect(0, 0, 100, 400));
    241 
    242  // Set up two snap points, 30 and 100.
    243  ScrollSnapInfo snap;
    244  snap.mScrollSnapStrictnessY = StyleScrollSnapStrictness::Mandatory;
    245  snap.mSnapportSize =
    246      CSSSize::ToAppUnits(layerVisibleRect[0].Size() * LayerToCSSScale(1.0));
    247  snap.mSnapTargets.AppendElement(ScrollSnapInfo::SnapTarget(
    248      Nothing(), Some(30 * AppUnitsPerCSSPixel()),
    249      CSSRect::ToAppUnits(CSSRect(0, 30, 10, 10)), StyleScrollSnapStop::Normal,
    250      ScrollSnapTargetId{1}));
    251  snap.mSnapTargets.AppendElement(ScrollSnapInfo::SnapTarget(
    252      Nothing(), Some(100 * AppUnitsPerCSSPixel()),
    253      CSSRect::ToAppUnits(CSSRect(0, 100, 10, 10)), StyleScrollSnapStop::Normal,
    254      ScrollSnapTargetId{2}));
    255 
    256  // Save the scroll snap info on the root APZC.
    257  ModifyFrameMetrics(root, [&](ScrollMetadata& aSm, FrameMetrics& aMetrics) {
    258    aSm.SetSnapInfo(ScrollSnapInfo(snap));
    259  });
    260 
    261  UniquePtr<ScopedLayerTreeRegistration> registration =
    262      MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
    263  UpdateHitTestingTree();
    264 
    265  RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root);
    266 
    267  // Send a series of pan gestures that a pan-end event happens at 65
    268  const ScreenIntPoint position = ScreenIntPoint(50, 30);
    269  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
    270  PanGesture(PanGestureInput::PANGESTURE_START, manager, position,
    271             ScreenPoint(0, 10), mcc->Time());
    272  mcc->AdvanceByMillis(5);
    273  apzc->AdvanceAnimations(mcc->GetSampleTime());
    274  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
    275  PanGesture(PanGestureInput::PANGESTURE_PAN, manager, position,
    276             ScreenPoint(0, 35), mcc->Time());
    277  mcc->AdvanceByMillis(5);
    278  apzc->AdvanceAnimations(mcc->GetSampleTime());
    279  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
    280  PanGesture(PanGestureInput::PANGESTURE_PAN, manager, position,
    281             ScreenPoint(0, 20), mcc->Time());
    282  mcc->AdvanceByMillis(5);
    283  apzc->AdvanceAnimations(mcc->GetSampleTime());
    284 
    285  // There should be positive velocity in this case.
    286  EXPECT_GT(apzc->GetVelocityVector().y, 0);
    287 
    288  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
    289  PanGesture(PanGestureInput::PANGESTURE_END, manager, position,
    290             ScreenPoint(0, 0), mcc->Time());
    291  mcc->AdvanceByMillis(5);
    292 
    293  // A smooth animation has been triggered by the pan-end event above.
    294  apzc->AssertInSmoothMsdScroll();
    295 
    296  apzc->AdvanceAnimationsUntilEnd();
    297  EXPECT_EQ(apzc->GetCurrentAsyncScrollOffset(
    298                    AsyncPanZoomController::eForEventHandling)
    299                .y,
    300            100);
    301 }
    302 #endif