michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=8 et tw=80 : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_layers_Axis_h michael@0: #define mozilla_layers_Axis_h michael@0: michael@0: #include // for int32_t michael@0: #include "Units.h" // for CSSRect, CSSPoint michael@0: #include "mozilla/TimeStamp.h" // for TimeDuration michael@0: #include "nsTArray.h" // for nsTArray michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: const float EPSILON = 0.0001f; michael@0: michael@0: class AsyncPanZoomController; michael@0: michael@0: /** michael@0: * Helper class to maintain each axis of movement (X,Y) for panning and zooming. michael@0: * Note that everything here is specific to one axis; that is, the X axis knows michael@0: * nothing about the Y axis and vice versa. michael@0: */ michael@0: class Axis { michael@0: public: michael@0: Axis(AsyncPanZoomController* aAsyncPanZoomController); michael@0: michael@0: enum Overscroll { michael@0: // Overscroll is not happening at all. michael@0: OVERSCROLL_NONE = 0, michael@0: // Overscroll is happening in the negative direction. This means either to michael@0: // the left or to the top depending on the axis. michael@0: OVERSCROLL_MINUS, michael@0: // Overscroll is happening in the positive direction. This means either to michael@0: // the right or to the bottom depending on the axis. michael@0: OVERSCROLL_PLUS, michael@0: // Overscroll is happening both ways. This only means something when the michael@0: // page is scaled out to a smaller size than the viewport. michael@0: OVERSCROLL_BOTH michael@0: }; michael@0: michael@0: /** michael@0: * Notify this Axis that a new touch has been received, including a time delta michael@0: * indicating how long it has been since the previous one. This triggers a michael@0: * recalculation of velocity. michael@0: */ michael@0: void UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeDelta); michael@0: michael@0: /** michael@0: * Notify this Axis that a touch has begun, i.e. the user has put their finger michael@0: * on the screen but has not yet tried to pan. michael@0: */ michael@0: void StartTouch(int32_t aPos); michael@0: michael@0: /** michael@0: * Notify this Axis that a touch has ended gracefully. This may perform michael@0: * recalculations of the axis velocity. michael@0: */ michael@0: void EndTouch(); michael@0: michael@0: /** michael@0: * Notify this Axis that a touch has ended forcefully. Useful for stopping michael@0: * flings when a user puts their finger down in the middle of one (i.e. to michael@0: * stop a previous touch including its fling so that a new one can take its michael@0: * place). michael@0: */ michael@0: void CancelTouch(); michael@0: michael@0: /** michael@0: * Takes a requested displacement to the position of this axis, and adjusts it michael@0: * to account for overscroll (which might decrease the displacement; this is michael@0: * to prevent the viewport from overscrolling the page rect), and axis locking michael@0: * (which might prevent any displacement from happening). If overscroll michael@0: * ocurred, its amount is written to |aOverscrollAmountOut|. michael@0: * The adjusted displacement is returned. michael@0: */ michael@0: float AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut); michael@0: michael@0: /** michael@0: * Gets the distance between the starting position of the touch supplied in michael@0: * startTouch() and the current touch from the last michael@0: * updateWithTouchAtDevicePoint(). michael@0: */ michael@0: float PanDistance(); michael@0: michael@0: /** michael@0: * Gets the distance between the starting position of the touch supplied in michael@0: * startTouch() and the supplied position. michael@0: */ michael@0: float PanDistance(float aPos); michael@0: michael@0: /** michael@0: * Applies friction during a fling, or cancels the fling if the velocity is michael@0: * too low. Returns true if the fling should continue to another frame, or michael@0: * false if it should end. |aDelta| is the amount of time that has passed michael@0: * since the last time friction was applied. michael@0: */ michael@0: bool FlingApplyFrictionOrCancel(const TimeDuration& aDelta); michael@0: michael@0: /* michael@0: * Returns true if the page is zoomed in to some degree along this axis such that scrolling is michael@0: * possible and this axis has not been scroll locked while panning. Otherwise, returns false. michael@0: */ michael@0: bool Scrollable(); michael@0: michael@0: void SetAxisLocked(bool aAxisLocked) { mAxisLocked = aAxisLocked; } michael@0: michael@0: /** michael@0: * Gets the overscroll state of the axis in its current position. michael@0: */ michael@0: Overscroll GetOverscroll(); michael@0: michael@0: /** michael@0: * If there is overscroll, returns the amount. Sign depends on in what michael@0: * direction it is overscrolling. Positive excess means that it is michael@0: * overscrolling in the positive direction, whereas negative excess means michael@0: * that it is overscrolling in the negative direction. If there is overscroll michael@0: * in both directions, this returns 0; it assumes that you check michael@0: * GetOverscroll() first. michael@0: */ michael@0: float GetExcess(); michael@0: michael@0: /** michael@0: * Gets the raw velocity of this axis at this moment. michael@0: */ michael@0: float GetVelocity(); michael@0: michael@0: /** michael@0: * Sets the raw velocity of this axis at this moment. michael@0: * Intended to be called only when the axis "takes over" a velocity from michael@0: * another APZC, in which case there are no touch points available to call michael@0: * UpdateWithTouchAtDevicePoint. In other circumstances, michael@0: * UpdateWithTouchAtDevicePoint should be used and the velocity calculated michael@0: * there. michael@0: */ michael@0: void SetVelocity(float aVelocity); michael@0: michael@0: /** michael@0: * Gets the overscroll state of the axis given an additional displacement. michael@0: * That is to say, if the given displacement is applied, this will tell you michael@0: * whether or not it will overscroll, and in what direction. michael@0: */ michael@0: Overscroll DisplacementWillOverscroll(float aDisplacement); michael@0: michael@0: /** michael@0: * If a displacement will overscroll the axis, this returns the amount and in michael@0: * what direction. Similar to GetExcess() but takes a displacement to apply. michael@0: */ michael@0: float DisplacementWillOverscrollAmount(float aDisplacement); michael@0: michael@0: /** michael@0: * If a scale will overscroll the axis, this returns the amount and in what michael@0: * direction. Similar to GetExcess() but takes a displacement to apply. michael@0: * michael@0: * |aFocus| is the point at which the scale is focused at. We will offset the michael@0: * scroll offset in such a way that it remains in the same place on the page michael@0: * relative. michael@0: */ michael@0: float ScaleWillOverscrollAmount(float aScale, float aFocus); michael@0: michael@0: /** michael@0: * Checks if an axis will overscroll in both directions by computing the michael@0: * content rect and checking that its height/width (depending on the axis) michael@0: * does not overextend past the viewport. michael@0: * michael@0: * This gets called by ScaleWillOverscroll(). michael@0: */ michael@0: bool ScaleWillOverscrollBothSides(float aScale); michael@0: michael@0: /** michael@0: * Returns whether there is room to pan on this axis in either direction. michael@0: */ michael@0: bool HasRoomToPan() const; michael@0: michael@0: float GetOrigin() const; michael@0: float GetCompositionLength() const; michael@0: float GetPageStart() const; michael@0: float GetPageLength() const; michael@0: float GetCompositionEnd() const; michael@0: float GetPageEnd() const; michael@0: michael@0: int32_t GetPos() const { return mPos; } michael@0: michael@0: virtual float GetPointOffset(const CSSPoint& aPoint) const = 0; michael@0: virtual float GetRectLength(const CSSRect& aRect) const = 0; michael@0: virtual float GetRectOffset(const CSSRect& aRect) const = 0; michael@0: michael@0: protected: michael@0: int32_t mPos; michael@0: int32_t mStartPos; michael@0: float mVelocity; michael@0: bool mAxisLocked; // Whether movement on this axis is locked. michael@0: AsyncPanZoomController* mAsyncPanZoomController; michael@0: nsTArray mVelocityQueue; michael@0: }; michael@0: michael@0: class AxisX : public Axis { michael@0: public: michael@0: AxisX(AsyncPanZoomController* mAsyncPanZoomController); michael@0: virtual float GetPointOffset(const CSSPoint& aPoint) const; michael@0: virtual float GetRectLength(const CSSRect& aRect) const; michael@0: virtual float GetRectOffset(const CSSRect& aRect) const; michael@0: }; michael@0: michael@0: class AxisY : public Axis { michael@0: public: michael@0: AxisY(AsyncPanZoomController* mAsyncPanZoomController); michael@0: virtual float GetPointOffset(const CSSPoint& aPoint) const; michael@0: virtual float GetRectLength(const CSSRect& aRect) const; michael@0: virtual float GetRectOffset(const CSSRect& aRect) const; michael@0: }; michael@0: michael@0: } michael@0: } michael@0: michael@0: #endif