gecko-dev/gfx/layers/ipc/AsyncPanZoomController.h

763 lines
28 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_AsyncPanZoomController_h
#define mozilla_layers_AsyncPanZoomController_h
#include "GeckoContentController.h"
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/Monitor.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Atomics.h"
#include "InputData.h"
#include "Axis.h"
#include "TaskThrottler.h"
#include "gfx3DMatrix.h"
#include "base/message_loop.h"
namespace mozilla {
namespace layers {
struct ScrollableLayerGuid;
class CompositorParent;
class GestureEventListener;
class ContainerLayer;
class ViewTransform;
class APZCTreeManager;
class AsyncPanZoomAnimation;
/**
* Controller for all panning and zooming logic. Any time a user input is
* detected and it must be processed in some way to affect what the user sees,
* it goes through here. Listens for any input event from InputData and can
* optionally handle WidgetGUIEvent-derived touch events, but this must be done
* on the main thread. Note that this class completely cross-platform.
*
* Input events originate on the UI thread of the platform that this runs on,
* and are then sent to this class. This class processes the event in some way;
* for example, a touch move will usually lead to a panning of content (though
* of course there are exceptions, such as if content preventDefaults the event,
* or if the target frame is not scrollable). The compositor interacts with this
* class by locking it and querying it for the current transform matrix based on
* the panning and zooming logic that was invoked on the UI thread.
*
* Currently, each outer DOM window (i.e. a website in a tab, but not any
* subframes) has its own AsyncPanZoomController. In the future, to support
* asynchronously scrolled subframes, we want to have one AsyncPanZoomController
* per frame.
*/
class AsyncPanZoomController {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomController)
typedef mozilla::MonitorAutoLock MonitorAutoLock;
public:
enum GestureBehavior {
// The platform code is responsible for forwarding gesture events here. We
// will not attempt to generate gesture events from MultiTouchInputs.
DEFAULT_GESTURES,
// An instance of GestureEventListener is used to detect gestures. This is
// handled completely internally within this class.
USE_GESTURE_DETECTOR
};
/**
* Constant describing the tolerance in distance we use, multiplied by the
* device DPI, before we start panning the screen. This is to prevent us from
* accidentally processing taps as touch moves, and from very short/accidental
* touches moving the screen.
*/
static float GetTouchStartTolerance();
AsyncPanZoomController(uint64_t aLayersId,
APZCTreeManager* aTreeManager,
GeckoContentController* aController,
GestureBehavior aGestures = DEFAULT_GESTURES);
~AsyncPanZoomController();
// --------------------------------------------------------------------------
// These methods must only be called on the gecko thread.
//
/**
* Read the various prefs and do any global initialization for all APZC instances.
* This must be run on the gecko thread before any APZC instances are actually
* used for anything meaningful.
*/
static void InitializeGlobalState();
// --------------------------------------------------------------------------
// These methods must only be called on the controller/UI thread.
//
/**
* General handler for incoming input events. Manipulates the frame metrics
* based on what type of input it is. For example, a PinchGestureEvent will
* cause scaling. This should only be called externally to this class.
* HandleInputEvent() should be used internally.
*/
nsEventStatus ReceiveInputEvent(const InputData& aEvent);
/**
* Updates the composition bounds, i.e. the dimensions of the final size of
* the frame this is tied to during composition onto, in device pixels. In
* general, this will just be:
* { x = 0, y = 0, width = surface.width, height = surface.height }, however
* there is no hard requirement for this.
*/
void UpdateCompositionBounds(const ScreenIntRect& aCompositionBounds);
/**
* Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
* in. The actual animation is done on the compositor thread after being set
* up.
*/
void ZoomToRect(CSSRect aRect);
/**
* If we have touch listeners, this should always be called when we know
* definitively whether or not content has preventDefaulted any touch events
* that have come in. If |aPreventDefault| is true, any touch events in the
* queue will be discarded.
*/
void ContentReceivedTouch(bool aPreventDefault);
/**
* Updates any zoom constraints contained in the <meta name="viewport"> tag.
* We try to obey everything it asks us elsewhere, but here we only handle
* minimum-scale, maximum-scale, and user-scalable.
*/
void UpdateZoomConstraints(bool aAllowZoom,
const CSSToScreenScale& aMinScale,
const CSSToScreenScale& aMaxScale);
/**
* Return the zoom constraints last set for this APZC (in the constructor
* or in UpdateZoomConstraints()).
*/
void GetZoomConstraints(bool* aAllowZoom,
CSSToScreenScale* aMinScale,
CSSToScreenScale* aMaxScale);
/**
* Schedules a runnable to run on the controller/UI thread at some time
* in the future.
*/
void PostDelayedTask(Task* aTask, int aDelayMs);
// --------------------------------------------------------------------------
// These methods must only be called on the compositor thread.
//
bool UpdateAnimation(const TimeStamp& aSampleTime);
/**
* The compositor calls this when it's about to draw pannable/zoomable content
* and is setting up transforms for compositing the layer tree. This is not
* idempotent. For example, a fling transform can be applied each time this is
* called (though not necessarily). |aSampleTime| is the time that this is
* sampled at; this is used for interpolating animations. Calling this sets a
* new transform in |aNewTransform| which should be multiplied to the transform
* in the shadow layer corresponding to this APZC.
*
* Return value indicates whether or not any currently running animation
* should continue. That is, if true, the compositor should schedule another
* composite.
*/
bool SampleContentTransformForFrame(const TimeStamp& aSampleTime,
ViewTransform* aNewTransform,
ScreenPoint& aScrollOffset);
/**
* A shadow layer update has arrived. |aLayerMetrics| is the new FrameMetrics
* for the container layer corresponding to this APZC.
* |aIsFirstPaint| is a flag passed from the shadow
* layers code indicating that the frame metrics being sent with this call are
* the initial metrics and the initial paint of the frame has just happened.
*/
void NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint);
/**
* The platform implementation must set the compositor parent so that we can
* request composites.
*/
void SetCompositorParent(CompositorParent* aCompositorParent);
// --------------------------------------------------------------------------
// These methods can be called from any thread.
//
/**
* Shut down the controller/UI thread state and prepare to be
* deleted (which may happen from any thread).
*/
void Destroy();
/**
* Returns true if Destroy() has already been called on this APZC instance.
*/
bool IsDestroyed();
/**
* Returns the incremental transformation corresponding to the async pan/zoom
* in progress. That is, when this transform is multiplied with the layer's
* existing transform, it will make the layer appear with the desired pan/zoom
* amount.
*/
ViewTransform GetCurrentAsyncTransform();
/**
* Returns the part of the async transform that will remain once Gecko does a
* repaint at the desired metrics. That is, in the steady state:
* gfx3DMatrix(GetCurrentAsyncTransform()) === GetNontransientAsyncTransform()
*/
gfx3DMatrix GetNontransientAsyncTransform();
/**
* Recalculates the displayport. Ideally, this should paint an area bigger
* than the composite-to dimensions so that when you scroll down, you don't
* checkerboard immediately. This includes a bunch of logic, including
* algorithms to bias painting in the direction of the velocity.
*/
static const CSSRect CalculatePendingDisplayPort(
const FrameMetrics& aFrameMetrics,
const gfx::Point& aVelocity,
const gfx::Point& aAcceleration,
double aEstimatedPaintDuration);
/**
* Send an mozbrowserasyncscroll event.
* *** The monitor must be held while calling this.
*/
void SendAsyncScrollEvent();
/**
* Handler for events which should not be intercepted by the touch listener.
* Does the work for ReceiveInputEvent().
*/
nsEventStatus HandleInputEvent(const InputData& aEvent);
/**
* Populates the provided object with the scrollable guid of this apzc.
*/
void GetGuid(ScrollableLayerGuid* aGuidOut);
/**
* Returns true if this APZC instance is for the layer identified by the guid.
*/
bool Matches(const ScrollableLayerGuid& aGuid);
/**
* Sync panning and zooming animation using a fixed frame time.
* This will ensure that we animate the APZC correctly with other external
* animations to the same timestamp.
*/
static void SetFrameTime(const TimeStamp& aMilliseconds);
/**
* Update mFrameMetrics.mScrollOffset to the given offset.
* This is necessary in cases where a scroll is not caused by user
* input (for example, a content scrollTo()).
*/
void UpdateScrollOffset(const CSSPoint& aScrollOffset);
void StartAnimation(AsyncPanZoomAnimation* aAnimation);
/**
* Cancels any currently running animation. Note that all this does is set the
* state of the AsyncPanZoomController back to NOTHING, but it is the
* animation's responsibility to check this before advancing.
*/
void CancelAnimation();
/**
* Attempt to scroll in response to a touch-move from |aStartPoint| to
* |aEndPoint|, which are in our (transformed) screen coordinates.
* Due to overscroll handling, there may not actually have been a touch-move
* at these points, but this function will scroll as if there had been.
* If this attempt causes overscroll (i.e. the layer cannot be scrolled
* by the entire amount requested), the overscroll is passed back to the
* tree manager via APZCTreeManager::DispatchScroll().
* |aOverscrollHandoffChainIndex| is used by the tree manager to keep track
* of which APZC to hand off the overscroll to; this function increments it
* and passes it on to APZCTreeManager::DispatchScroll() in the event of
* overscroll.
*/
void AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
uint32_t aOverscrollHandoffChainIndex = 0);
/**
* A helper function for calling APZCTreeManager::DispatchScroll().
* Guards against the case where the APZC is being concurrently destroyed
* (and thus mTreeManager is being nulled out).
*/
void CallDispatchScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
uint32_t aOverscrollHandoffChainIndex);
/**
* Returns whether this APZC is for an element marked with the 'scrollgrab'
* attribute.
*/
bool HasScrollgrab() const { return mFrameMetrics.mHasScrollgrab; }
protected:
/**
* Helper method for touches beginning. Sets everything up for panning and any
* multitouch gestures.
*/
nsEventStatus OnTouchStart(const MultiTouchInput& aEvent);
/**
* Helper method for touches moving. Does any transforms needed when panning.
*/
nsEventStatus OnTouchMove(const MultiTouchInput& aEvent);
/**
* Helper method for touches ending. Redraws the screen if necessary and does
* any cleanup after a touch has ended.
*/
nsEventStatus OnTouchEnd(const MultiTouchInput& aEvent);
/**
* Helper method for touches being cancelled. Treated roughly the same as a
* touch ending (OnTouchEnd()).
*/
nsEventStatus OnTouchCancel(const MultiTouchInput& aEvent);
/**
* Helper method for scales beginning. Distinct from the OnTouch* handlers in
* that this implies some outside implementation has determined that the user
* is pinching.
*/
nsEventStatus OnScaleBegin(const PinchGestureInput& aEvent);
/**
* Helper method for scaling. As the user moves their fingers when pinching,
* this changes the scale of the page.
*/
nsEventStatus OnScale(const PinchGestureInput& aEvent);
/**
* Helper method for scales ending. Redraws the screen if necessary and does
* any cleanup after a scale has ended.
*/
nsEventStatus OnScaleEnd(const PinchGestureInput& aEvent);
/**
* Helper method for long press gestures.
*
* XXX: Implement this.
*/
nsEventStatus OnLongPress(const TapGestureInput& aEvent);
/**
* Helper method for single tap gestures.
*
* XXX: Implement this.
*/
nsEventStatus OnSingleTapUp(const TapGestureInput& aEvent);
/**
* Helper method for a single tap confirmed.
*
* XXX: Implement this.
*/
nsEventStatus OnSingleTapConfirmed(const TapGestureInput& aEvent);
/**
* Helper method for double taps.
*
* XXX: Implement this.
*/
nsEventStatus OnDoubleTap(const TapGestureInput& aEvent);
/**
* Helper method to cancel any gesture currently going to Gecko. Used
* primarily when a user taps the screen over some clickable content but then
* pans down instead of letting go (i.e. to cancel a previous touch so that a
* new one can properly take effect.
*/
nsEventStatus OnCancelTap(const TapGestureInput& aEvent);
/**
* Scrolls the viewport by an X,Y offset.
*/
void ScrollBy(const CSSPoint& aOffset);
/**
* Scales the viewport by an amount (note that it multiplies this scale in to
* the current scale, it doesn't set it to |aScale|). Also considers a focus
* point so that the page zooms inward/outward from that point.
*/
void ScaleWithFocus(float aScale,
const CSSPoint& aFocus);
/**
* Schedules a composite on the compositor thread. Wrapper for
* CompositorParent::ScheduleRenderOnCompositorThread().
*/
void ScheduleComposite();
/**
* Gets the displacement of the current touch since it began. That is, it is
* the distance between the current position and the initial position of the
* current touch (this only makes sense if a touch is currently happening and
* OnTouchMove() is being invoked).
*/
float PanDistance();
/**
* Gets a vector of the velocities of each axis.
*/
const gfx::Point GetVelocityVector();
/**
* Gets a vector of the acceleration factors of each axis.
*/
const gfx::Point GetAccelerationVector();
/**
* Gets a reference to the first touch point from a MultiTouchInput. This
* gets only the first one and assumes the rest are either missing or not
* relevant.
*/
ScreenIntPoint& GetFirstTouchScreenPoint(const MultiTouchInput& aEvent);
/**
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
* state and starts actually panning us.
*/
nsEventStatus StartPanning(const MultiTouchInput& aStartPoint);
/**
* Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for
* both axes and factors in the time delta from the last update.
*/
void UpdateWithTouchAtDevicePoint(const MultiTouchInput& aEvent);
/**
* Does any panning required due to a new touch event.
*/
void TrackTouch(const MultiTouchInput& aEvent);
/**
* Attempts to enlarge the displayport along a single axis. Returns whether or
* not the displayport was enlarged. This will fail in circumstances where the
* velocity along that axis is not high enough to need any changes. The
* displayport metrics are expected to be passed into |aDisplayPortOffset| and
* |aDisplayPortLength|. If enlarged, these will be updated with the new
* metrics.
*/
static bool EnlargeDisplayPortAlongAxis(float aSkateSizeMultiplier,
double aEstimatedPaintDuration,
float aCompositionBounds,
float aVelocity,
float aAcceleration,
float* aDisplayPortOffset,
float* aDisplayPortLength);
/**
* Utility function to send updated FrameMetrics to Gecko so that it can paint
* the displayport area. Calls into GeckoContentController to do the actual
* work. Note that only one paint request can be active at a time. If a paint
* request is made while a paint is currently happening, it gets queued up. If
* a new paint request arrives before a paint is completed, the old request
* gets discarded.
*/
void RequestContentRepaint();
/**
* Tell the paint throttler to request a content repaint with the given
* metrics. (Helper function used by RequestContentRepaint.)
*/
void ScheduleContentRepaint(FrameMetrics &aFrameMetrics);
/**
* Advances a fling by an interpolated amount based on the passed in |aDelta|.
* This should be called whenever sampling the content transform for this
* frame. Returns true if the fling animation should be advanced by one frame,
* or false if there is no fling or the fling has ended.
*/
bool DoFling(const TimeDuration& aDelta);
/**
* Gets the current frame metrics. This is *not* the Gecko copy stored in the
* layers code.
*/
const FrameMetrics& GetFrameMetrics();
/**
* Timeout function for touch listeners. This should be called on a timer
* after we get our first touch event in a batch, under the condition that we
* have touch listeners. If a notification comes indicating whether or not
* content preventDefaulted a series of touch events before the timeout, the
* timeout should be cancelled.
*/
void TimeoutTouchListeners();
/**
* Timeout function for mozbrowserasyncscroll event. Because we throttle
* mozbrowserasyncscroll events in some conditions, this function ensures
* that the last mozbrowserasyncscroll event will be fired after a period of
* time.
*/
void FireAsyncScrollOnTimeout();
private:
enum PanZoomState {
NOTHING, /* no touch-start events received */
FLING, /* all touches removed, but we're still scrolling page */
TOUCHING, /* one touch-start event received */
PANNING, /* panning the frame */
PANNING_LOCKED_X, /* touch-start followed by move (i.e. panning with axis lock) X axis */
PANNING_LOCKED_Y, /* as above for Y axis */
CROSS_SLIDING_X, /* Panning disabled while user does a horizontal gesture
on a vertically-scrollable view. This used for the
Windows Metro "cross-slide" gesture. */
CROSS_SLIDING_Y, /* as above for Y axis */
PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */
ANIMATING_ZOOM, /* animated zoom to a new rect */
WAITING_LISTENERS, /* a state halfway between NOTHING and TOUCHING - the user has
put a finger down, but we don't yet know if a touch listener has
prevented the default actions yet. we still need to abort animations. */
};
/**
* Helper to set the current state. Holds the monitor before actually setting
* it and fires content controller events based on state changes. Always set
* the state using this call, do not set it directly.
*/
void SetState(PanZoomState aState);
/**
* Convert ScreenPoint relative to this APZC to CSSIntPoint relative
* to the parent document. This excludes the transient compositor transform.
* NOTE: This must be converted to CSSIntPoint relative to the child
* document before sending over IPC.
*/
bool ConvertToGecko(const ScreenPoint& aPoint, CSSIntPoint* aOut);
/**
* Internal helpers for checking general state of this apzc.
*/
bool IsTransformingState(PanZoomState aState);
bool IsPanningState(PanZoomState mState);
enum AxisLockMode {
FREE, /* No locking at all */
STANDARD, /* Default axis locking mode that remains locked until pan ends*/
STICKY, /* Allow lock to be broken, with hysteresis */
};
static AxisLockMode GetAxisLockMode();
uint64_t mLayersId;
nsRefPtr<CompositorParent> mCompositorParent;
TaskThrottler mPaintThrottler;
/* Access to the following two fields is protected by the mRefPtrMonitor,
since they are accessed on the UI thread but can be cleared on the
compositor thread. */
nsRefPtr<GeckoContentController> mGeckoContentController;
nsRefPtr<GestureEventListener> mGestureEventListener;
Monitor mRefPtrMonitor;
/* Utility functions that return a addrefed pointer to the corresponding fields. */
already_AddRefed<GeckoContentController> GetGeckoContentController();
already_AddRefed<GestureEventListener> GetGestureEventListener();
protected:
// Both |mFrameMetrics| and |mLastContentPaintMetrics| are protected by the
// monitor. Do not read from or modify either of them without locking.
FrameMetrics mFrameMetrics;
// Protects |mFrameMetrics|, |mLastContentPaintMetrics|, and |mState|.
// Before manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the
// monitor should be held. When setting |mState|, either the SetState()
// function can be used, or the monitor can be held and then |mState| updated.
ReentrantMonitor mMonitor;
private:
// Metrics of the container layer corresponding to this APZC. This is
// stored here so that it is accessible from the UI/controller thread.
// These are the metrics at last content paint, the most recent
// values we were notified of in NotifyLayersUpdate(). Since it represents
// the Gecko state, it should be used as a basis for untransformation when
// sending messages back to Gecko.
FrameMetrics mLastContentPaintMetrics;
// The last metrics that we requested a paint for. These are used to make sure
// that we're not requesting a paint of the same thing that's already drawn.
// If we don't do this check, we don't get a ShadowLayersUpdated back.
FrameMetrics mLastPaintRequestMetrics;
nsTArray<MultiTouchInput> mTouchQueue;
CancelableTask* mTouchListenerTimeoutTask;
AxisX mX;
AxisY mY;
// Most up-to-date constraints on zooming. These should always be reasonable
// values; for example, allowing a min zoom of 0.0 can cause very bad things
// to happen.
bool mAllowZoom;
CSSToScreenScale mMinZoom;
CSSToScreenScale mMaxZoom;
// The last time the compositor has sampled the content transform for this
// frame.
TimeStamp mLastSampleTime;
// The last time a touch event came through on the UI thread.
uint32_t mLastEventTime;
// Stores the previous focus point if there is a pinch gesture happening. Used
// to allow panning by moving multiple fingers (thus moving the focus point).
ScreenPoint mLastZoomFocus;
// Stores the state of panning and zooming this frame. This is protected by
// |mMonitor|; that is, it should be held whenever this is updated.
PanZoomState mState;
// The last time and offset we fire the mozbrowserasyncscroll event when
// compositor has sampled the content transform for this frame.
TimeStamp mLastAsyncScrollTime;
CSSPoint mLastAsyncScrollOffset;
// The current offset drawn on the screen, it may not be sent since we have
// throttling policy for mozbrowserasyncscroll event.
CSSPoint mCurrentAsyncScrollOffset;
// The delay task triggered by the throttling mozbrowserasyncscroll event
// ensures the last mozbrowserasyncscroll event is always been fired.
CancelableTask* mAsyncScrollTimeoutTask;
// Flag used to determine whether or not we should try to enter the
// WAITING_LISTENERS state. This is used in the case that we are processing a
// queued up event block. If set, this means that we are handling this queue
// and we don't want to queue the events back up again.
bool mHandlingTouchQueue;
RefPtr<AsyncPanZoomAnimation> mAnimation;
friend class Axis;
/* The functions and members in this section are used to build a tree
* structure out of APZC instances. This tree can only be walked or
* manipulated while holding the lock in the associated APZCTreeManager
* instance.
*/
public:
void SetLastChild(AsyncPanZoomController* child) {
mLastChild = child;
if (child) {
child->mParent = this;
}
}
void SetPrevSibling(AsyncPanZoomController* sibling) {
mPrevSibling = sibling;
if (sibling) {
sibling->mParent = mParent;
}
}
AsyncPanZoomController* GetLastChild() const { return mLastChild; }
AsyncPanZoomController* GetPrevSibling() const { return mPrevSibling; }
AsyncPanZoomController* GetParent() const { return mParent; }
/* Returns true if there is no APZC higher in the tree with the same
* layers id.
*/
bool IsRootForLayersId() const {
return !mParent || (mParent->mLayersId != mLayersId);
}
bool IsRootForLayersId(const uint64_t& aLayersId) const {
return (mLayersId == aLayersId) && IsRootForLayersId();
}
private:
// This is a raw pointer to avoid introducing a reference cycle between
// AsyncPanZoomController and APZCTreeManager. Since these objects don't
// live on the main thread, we can't use the cycle collector with them.
// The APZCTreeManager owns the lifetime of the APZCs, so nulling this
// pointer out in Destroy() will prevent accessing deleted memory.
Atomic<APZCTreeManager*> mTreeManager;
nsRefPtr<AsyncPanZoomController> mLastChild;
nsRefPtr<AsyncPanZoomController> mPrevSibling;
nsRefPtr<AsyncPanZoomController> mParent;
/* The functions and members in this section are used to maintain the
* area that this APZC instance is responsible for. This is used when
* hit-testing to see which APZC instance should handle touch events.
*/
public:
void SetLayerHitTestData(const ScreenRect& aRect, const gfx3DMatrix& aTransformToLayer,
const gfx3DMatrix& aTransformForLayer) {
mVisibleRect = aRect;
mAncestorTransform = aTransformToLayer;
mCSSTransform = aTransformForLayer;
}
gfx3DMatrix GetAncestorTransform() const {
return mAncestorTransform;
}
gfx3DMatrix GetCSSTransform() const {
return mCSSTransform;
}
bool VisibleRegionContains(const ScreenPoint& aPoint) const {
return mVisibleRect.Contains(aPoint);
}
private:
/* This is the visible region of the layer that this APZC corresponds to, in
* that layer's screen pixels (the same coordinate system in which this APZC
* receives events in ReceiveInputEvent()). */
ScreenRect mVisibleRect;
/* This is the cumulative CSS transform for all the layers between the parent
* APZC and this one (not inclusive) */
gfx3DMatrix mAncestorTransform;
/* This is the CSS transform for this APZC's layer. */
gfx3DMatrix mCSSTransform;
};
class AsyncPanZoomAnimation {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomAnimation)
public:
AsyncPanZoomAnimation(const TimeDuration& aRepaintInterval =
TimeDuration::Forever())
: mRepaintInterval(aRepaintInterval)
{ }
virtual ~AsyncPanZoomAnimation()
{ }
virtual bool Sample(FrameMetrics& aFrameMetrics,
const TimeDuration& aDelta) = 0;
/**
* Specifies how frequently (at most) we want to do repaints during the
* animation sequence. TimeDuration::Forever() will cause it to only repaint
* at the end of the animation.
*/
TimeDuration mRepaintInterval;
};
}
}
#endif // mozilla_layers_PanZoomController_h