gfx/layers/apz/src/Axis.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set sw=2 ts=8 et tw=80 : */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "Axis.h"
michael@0 8 #include <math.h> // for fabsf, pow, powf
michael@0 9 #include <algorithm> // for max
michael@0 10 #include "AsyncPanZoomController.h" // for AsyncPanZoomController
michael@0 11 #include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager
michael@0 12 #include "FrameMetrics.h" // for FrameMetrics
michael@0 13 #include "mozilla/Attributes.h" // for MOZ_FINAL
michael@0 14 #include "mozilla/Preferences.h" // for Preferences
michael@0 15 #include "mozilla/gfx/Rect.h" // for RoundedIn
michael@0 16 #include "mozilla/mozalloc.h" // for operator new
michael@0 17 #include "nsMathUtils.h" // for NS_lround
michael@0 18 #include "nsThreadUtils.h" // for NS_DispatchToMainThread, etc
michael@0 19 #include "nscore.h" // for NS_IMETHOD
michael@0 20 #include "gfxPrefs.h" // for the preferences
michael@0 21
michael@0 22 namespace mozilla {
michael@0 23 namespace layers {
michael@0 24
michael@0 25 Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
michael@0 26 : mPos(0),
michael@0 27 mVelocity(0.0f),
michael@0 28 mAxisLocked(false),
michael@0 29 mAsyncPanZoomController(aAsyncPanZoomController)
michael@0 30 {
michael@0 31 }
michael@0 32
michael@0 33 void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeDelta) {
michael@0 34 float newVelocity = mAxisLocked ? 0 : (mPos - aPos) / aTimeDelta.ToMilliseconds();
michael@0 35 if (gfxPrefs::APZMaxVelocity() > 0.0f) {
michael@0 36 newVelocity = std::min(newVelocity, gfxPrefs::APZMaxVelocity() * APZCTreeManager::GetDPI());
michael@0 37 }
michael@0 38
michael@0 39 mVelocity = newVelocity;
michael@0 40 mPos = aPos;
michael@0 41
michael@0 42 // Limit queue size pased on pref
michael@0 43 mVelocityQueue.AppendElement(mVelocity);
michael@0 44 if (mVelocityQueue.Length() > gfxPrefs::APZMaxVelocityQueueSize()) {
michael@0 45 mVelocityQueue.RemoveElementAt(0);
michael@0 46 }
michael@0 47 }
michael@0 48
michael@0 49 void Axis::StartTouch(int32_t aPos) {
michael@0 50 mStartPos = aPos;
michael@0 51 mPos = aPos;
michael@0 52 mAxisLocked = false;
michael@0 53 }
michael@0 54
michael@0 55 float Axis::AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut) {
michael@0 56 if (mAxisLocked) {
michael@0 57 aOverscrollAmountOut = 0;
michael@0 58 return 0;
michael@0 59 }
michael@0 60
michael@0 61 float displacement = aDisplacement;
michael@0 62
michael@0 63 // If this displacement will cause an overscroll, throttle it. Can potentially
michael@0 64 // bring it to 0 even if the velocity is high.
michael@0 65 if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {
michael@0 66 // No need to have a velocity along this axis anymore; it won't take us
michael@0 67 // anywhere, so we're just spinning needlessly.
michael@0 68 mVelocity = 0.0f;
michael@0 69 aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement);
michael@0 70 displacement -= aOverscrollAmountOut;
michael@0 71 }
michael@0 72 return displacement;
michael@0 73 }
michael@0 74
michael@0 75 float Axis::PanDistance() {
michael@0 76 return fabsf(mPos - mStartPos);
michael@0 77 }
michael@0 78
michael@0 79 float Axis::PanDistance(float aPos) {
michael@0 80 return fabsf(aPos - mStartPos);
michael@0 81 }
michael@0 82
michael@0 83 void Axis::EndTouch() {
michael@0 84 // Calculate the mean velocity and empty the queue.
michael@0 85 int count = mVelocityQueue.Length();
michael@0 86 if (count) {
michael@0 87 mVelocity = 0;
michael@0 88 while (!mVelocityQueue.IsEmpty()) {
michael@0 89 mVelocity += mVelocityQueue[0];
michael@0 90 mVelocityQueue.RemoveElementAt(0);
michael@0 91 }
michael@0 92 mVelocity /= count;
michael@0 93 }
michael@0 94 }
michael@0 95
michael@0 96 void Axis::CancelTouch() {
michael@0 97 mVelocity = 0.0f;
michael@0 98 while (!mVelocityQueue.IsEmpty()) {
michael@0 99 mVelocityQueue.RemoveElementAt(0);
michael@0 100 }
michael@0 101 }
michael@0 102
michael@0 103 bool Axis::Scrollable() {
michael@0 104 if (mAxisLocked) {
michael@0 105 return false;
michael@0 106 }
michael@0 107 return GetCompositionLength() < GetPageLength();
michael@0 108 }
michael@0 109
michael@0 110 bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) {
michael@0 111 if (fabsf(mVelocity) <= gfxPrefs::APZFlingStoppedThreshold()) {
michael@0 112 // If the velocity is very low, just set it to 0 and stop the fling,
michael@0 113 // otherwise we'll just asymptotically approach 0 and the user won't
michael@0 114 // actually see any changes.
michael@0 115 mVelocity = 0.0f;
michael@0 116 return false;
michael@0 117 } else {
michael@0 118 mVelocity *= pow(1.0f - gfxPrefs::APZFlingFriction(), float(aDelta.ToMilliseconds()));
michael@0 119 }
michael@0 120 return true;
michael@0 121 }
michael@0 122
michael@0 123 Axis::Overscroll Axis::GetOverscroll() {
michael@0 124 // If the current pan takes the window to the left of or above the current
michael@0 125 // page rect.
michael@0 126 bool minus = GetOrigin() < GetPageStart();
michael@0 127 // If the current pan takes the window to the right of or below the current
michael@0 128 // page rect.
michael@0 129 bool plus = GetCompositionEnd() > GetPageEnd();
michael@0 130 if (minus && plus) {
michael@0 131 return OVERSCROLL_BOTH;
michael@0 132 }
michael@0 133 if (minus) {
michael@0 134 return OVERSCROLL_MINUS;
michael@0 135 }
michael@0 136 if (plus) {
michael@0 137 return OVERSCROLL_PLUS;
michael@0 138 }
michael@0 139 return OVERSCROLL_NONE;
michael@0 140 }
michael@0 141
michael@0 142 float Axis::GetExcess() {
michael@0 143 switch (GetOverscroll()) {
michael@0 144 case OVERSCROLL_MINUS: return GetOrigin() - GetPageStart();
michael@0 145 case OVERSCROLL_PLUS: return GetCompositionEnd() - GetPageEnd();
michael@0 146 case OVERSCROLL_BOTH: return (GetCompositionEnd() - GetPageEnd()) +
michael@0 147 (GetPageStart() - GetOrigin());
michael@0 148 default: return 0;
michael@0 149 }
michael@0 150 }
michael@0 151
michael@0 152 Axis::Overscroll Axis::DisplacementWillOverscroll(float aDisplacement) {
michael@0 153 // If the current pan plus a displacement takes the window to the left of or
michael@0 154 // above the current page rect.
michael@0 155 bool minus = GetOrigin() + aDisplacement < GetPageStart();
michael@0 156 // If the current pan plus a displacement takes the window to the right of or
michael@0 157 // below the current page rect.
michael@0 158 bool plus = GetCompositionEnd() + aDisplacement > GetPageEnd();
michael@0 159 if (minus && plus) {
michael@0 160 return OVERSCROLL_BOTH;
michael@0 161 }
michael@0 162 if (minus) {
michael@0 163 return OVERSCROLL_MINUS;
michael@0 164 }
michael@0 165 if (plus) {
michael@0 166 return OVERSCROLL_PLUS;
michael@0 167 }
michael@0 168 return OVERSCROLL_NONE;
michael@0 169 }
michael@0 170
michael@0 171 float Axis::DisplacementWillOverscrollAmount(float aDisplacement) {
michael@0 172 switch (DisplacementWillOverscroll(aDisplacement)) {
michael@0 173 case OVERSCROLL_MINUS: return (GetOrigin() + aDisplacement) - GetPageStart();
michael@0 174 case OVERSCROLL_PLUS: return (GetCompositionEnd() + aDisplacement) - GetPageEnd();
michael@0 175 // Don't handle overscrolled in both directions; a displacement can't cause
michael@0 176 // this, it must have already been zoomed out too far.
michael@0 177 default: return 0;
michael@0 178 }
michael@0 179 }
michael@0 180
michael@0 181 float Axis::ScaleWillOverscrollAmount(float aScale, float aFocus) {
michael@0 182 float originAfterScale = (GetOrigin() + aFocus) - (aFocus / aScale);
michael@0 183
michael@0 184 bool both = ScaleWillOverscrollBothSides(aScale);
michael@0 185 bool minus = originAfterScale < GetPageStart();
michael@0 186 bool plus = (originAfterScale + (GetCompositionLength() / aScale)) > GetPageEnd();
michael@0 187
michael@0 188 if ((minus && plus) || both) {
michael@0 189 // If we ever reach here it's a bug in the client code.
michael@0 190 MOZ_ASSERT(false, "In an OVERSCROLL_BOTH condition in ScaleWillOverscrollAmount");
michael@0 191 return 0;
michael@0 192 }
michael@0 193 if (minus) {
michael@0 194 return originAfterScale - GetPageStart();
michael@0 195 }
michael@0 196 if (plus) {
michael@0 197 return originAfterScale + (GetCompositionLength() / aScale) - GetPageEnd();
michael@0 198 }
michael@0 199 return 0;
michael@0 200 }
michael@0 201
michael@0 202 float Axis::GetVelocity() {
michael@0 203 return mAxisLocked ? 0 : mVelocity;
michael@0 204 }
michael@0 205
michael@0 206 void Axis::SetVelocity(float aVelocity) {
michael@0 207 mVelocity = aVelocity;
michael@0 208 }
michael@0 209
michael@0 210 float Axis::GetCompositionEnd() const {
michael@0 211 return GetOrigin() + GetCompositionLength();
michael@0 212 }
michael@0 213
michael@0 214 float Axis::GetPageEnd() const {
michael@0 215 return GetPageStart() + GetPageLength();
michael@0 216 }
michael@0 217
michael@0 218 float Axis::GetOrigin() const {
michael@0 219 CSSPoint origin = mAsyncPanZoomController->GetFrameMetrics().GetScrollOffset();
michael@0 220 return GetPointOffset(origin);
michael@0 221 }
michael@0 222
michael@0 223 float Axis::GetCompositionLength() const {
michael@0 224 const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
michael@0 225 return GetRectLength(metrics.CalculateCompositedRectInCssPixels());
michael@0 226 }
michael@0 227
michael@0 228 float Axis::GetPageStart() const {
michael@0 229 CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
michael@0 230 return GetRectOffset(pageRect);
michael@0 231 }
michael@0 232
michael@0 233 float Axis::GetPageLength() const {
michael@0 234 CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
michael@0 235 return GetRectLength(pageRect);
michael@0 236 }
michael@0 237
michael@0 238 bool Axis::ScaleWillOverscrollBothSides(float aScale) {
michael@0 239 const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
michael@0 240
michael@0 241 CSSToParentLayerScale scale(metrics.GetZoomToParent().scale * aScale);
michael@0 242 CSSRect cssCompositionBounds = metrics.mCompositionBounds / scale;
michael@0 243
michael@0 244 return GetRectLength(metrics.mScrollableRect) < GetRectLength(cssCompositionBounds);
michael@0 245 }
michael@0 246
michael@0 247 bool Axis::HasRoomToPan() const {
michael@0 248 return GetOrigin() > GetPageStart()
michael@0 249 || GetCompositionEnd() < GetPageEnd();
michael@0 250 }
michael@0 251
michael@0 252
michael@0 253 AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
michael@0 254 : Axis(aAsyncPanZoomController)
michael@0 255 {
michael@0 256
michael@0 257 }
michael@0 258
michael@0 259 float AxisX::GetPointOffset(const CSSPoint& aPoint) const
michael@0 260 {
michael@0 261 return aPoint.x;
michael@0 262 }
michael@0 263
michael@0 264 float AxisX::GetRectLength(const CSSRect& aRect) const
michael@0 265 {
michael@0 266 return aRect.width;
michael@0 267 }
michael@0 268
michael@0 269 float AxisX::GetRectOffset(const CSSRect& aRect) const
michael@0 270 {
michael@0 271 return aRect.x;
michael@0 272 }
michael@0 273
michael@0 274 AxisY::AxisY(AsyncPanZoomController* aAsyncPanZoomController)
michael@0 275 : Axis(aAsyncPanZoomController)
michael@0 276 {
michael@0 277
michael@0 278 }
michael@0 279
michael@0 280 float AxisY::GetPointOffset(const CSSPoint& aPoint) const
michael@0 281 {
michael@0 282 return aPoint.y;
michael@0 283 }
michael@0 284
michael@0 285 float AxisY::GetRectLength(const CSSRect& aRect) const
michael@0 286 {
michael@0 287 return aRect.height;
michael@0 288 }
michael@0 289
michael@0 290 float AxisY::GetRectOffset(const CSSRect& aRect) const
michael@0 291 {
michael@0 292 return aRect.y;
michael@0 293 }
michael@0 294
michael@0 295 }
michael@0 296 }

mercurial