SimpleVelocityTracker.cpp (5129B)
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 "SimpleVelocityTracker.h" 8 9 #include "mozilla/ServoStyleConsts.h" // for StyleComputedTimingFunction 10 #include "mozilla/StaticPrefs_apz.h" 11 #include "mozilla/StaticPtr.h" // for StaticAutoPtr 12 13 static mozilla::LazyLogModule sApzSvtLog("apz.simplevelocitytracker"); 14 #define SVT_LOG(...) MOZ_LOG(sApzSvtLog, LogLevel::Debug, (__VA_ARGS__)) 15 16 namespace mozilla { 17 namespace layers { 18 19 // When we compute the velocity we do so by taking two input events and 20 // dividing the distance delta over the time delta. In some cases the time 21 // delta can be really small, which can make the velocity computation very 22 // volatile. To avoid this we impose a minimum time delta below which we do 23 // not recompute the velocity. 24 MOZ_RUNINIT const TimeDuration MIN_VELOCITY_SAMPLE_TIME = 25 TimeDuration::FromMilliseconds(5); 26 27 extern StaticAutoPtr<StyleComputedTimingFunction> gVelocityCurveFunction; 28 29 SimpleVelocityTracker::SimpleVelocityTracker(Axis* aAxis) 30 : mAxis(aAxis), mVelocitySamplePos(0) {} 31 32 void SimpleVelocityTracker::StartTracking(ParentLayerCoord aPos, 33 TimeStamp aTimestamp) { 34 Clear(); 35 mVelocitySampleTime = aTimestamp; 36 mVelocitySamplePos = aPos; 37 } 38 39 Maybe<float> SimpleVelocityTracker::AddPosition(ParentLayerCoord aPos, 40 TimeStamp aTimestamp) { 41 if (aTimestamp <= mVelocitySampleTime + MIN_VELOCITY_SAMPLE_TIME) { 42 // See also the comment on MIN_VELOCITY_SAMPLE_TIME. 43 // We don't update either mVelocitySampleTime or mVelocitySamplePos so that 44 // eventually when we do get an event with the required time delta we use 45 // the corresponding distance delta as well. 46 SVT_LOG("%p|%s skipping velocity computation for small time delta %f ms\n", 47 mAxis->OpaqueApzcPointer(), mAxis->Name(), 48 (aTimestamp - mVelocitySampleTime).ToMilliseconds()); 49 return Nothing(); 50 } 51 52 float newVelocity = 53 (float)(mVelocitySamplePos - aPos) / 54 (float)(aTimestamp - mVelocitySampleTime).ToMilliseconds(); 55 56 newVelocity = ApplyFlingCurveToVelocity(newVelocity); 57 58 SVT_LOG("%p|%s updating velocity to %f with touch\n", 59 mAxis->OpaqueApzcPointer(), mAxis->Name(), newVelocity); 60 mVelocitySampleTime = aTimestamp; 61 mVelocitySamplePos = aPos; 62 63 AddVelocityToQueue(aTimestamp, newVelocity); 64 65 return Some(newVelocity); 66 } 67 68 Maybe<float> SimpleVelocityTracker::ComputeVelocity(TimeStamp aTimestamp) { 69 float velocity = 0; 70 int count = 0; 71 for (const auto& e : mVelocityQueue) { 72 TimeDuration timeDelta = (aTimestamp - e.first); 73 if (timeDelta < TimeDuration::FromMilliseconds( 74 StaticPrefs::apz_velocity_relevance_time_ms())) { 75 count++; 76 velocity += e.second; 77 } 78 } 79 mVelocityQueue.Clear(); 80 if (count > 1) { 81 velocity /= count; 82 } 83 return Some(velocity); 84 } 85 86 void SimpleVelocityTracker::Clear() { mVelocityQueue.Clear(); } 87 88 void SimpleVelocityTracker::AddVelocityToQueue(TimeStamp aTimestamp, 89 float aVelocity) { 90 mVelocityQueue.AppendElement(std::make_pair(aTimestamp, aVelocity)); 91 if (mVelocityQueue.Length() > 92 StaticPrefs::apz_max_velocity_queue_size_AtStartup()) { 93 mVelocityQueue.RemoveElementAt(0); 94 } 95 } 96 97 float SimpleVelocityTracker::ApplyFlingCurveToVelocity(float aVelocity) const { 98 float newVelocity = aVelocity; 99 if (StaticPrefs::apz_max_velocity_inches_per_ms() > 0.0f) { 100 bool velocityIsNegative = (newVelocity < 0); 101 newVelocity = fabs(newVelocity); 102 103 float maxVelocity = 104 mAxis->ToLocalVelocity(StaticPrefs::apz_max_velocity_inches_per_ms()); 105 newVelocity = std::min(newVelocity, maxVelocity); 106 107 if (StaticPrefs::apz_fling_curve_threshold_inches_per_ms() > 0.0f && 108 StaticPrefs::apz_fling_curve_threshold_inches_per_ms() < 109 StaticPrefs::apz_max_velocity_inches_per_ms()) { 110 float curveThreshold = mAxis->ToLocalVelocity( 111 StaticPrefs::apz_fling_curve_threshold_inches_per_ms()); 112 if (newVelocity > curveThreshold) { 113 // here, 0 < curveThreshold < newVelocity <= maxVelocity, so we apply 114 // the curve 115 float scale = maxVelocity - curveThreshold; 116 float funcInput = (newVelocity - curveThreshold) / scale; 117 float funcOutput = 118 gVelocityCurveFunction->At(funcInput, /* aBeforeFlag = */ false); 119 float curvedVelocity = (funcOutput * scale) + curveThreshold; 120 SVT_LOG("%p|%s curving up velocity from %f to %f\n", 121 mAxis->OpaqueApzcPointer(), mAxis->Name(), newVelocity, 122 curvedVelocity); 123 newVelocity = curvedVelocity; 124 } 125 } 126 127 if (velocityIsNegative) { 128 newVelocity = -newVelocity; 129 } 130 } 131 132 return newVelocity; 133 } 134 135 } // namespace layers 136 } // namespace mozilla