diff -r 000000000000 -r 6474c204b198 gfx/layers/apz/src/AsyncPanZoomController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/layers/apz/src/AsyncPanZoomController.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,984 @@ +/* -*- 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 "CrossProcessMutex.h" +#include "mozilla/layers/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 ipc { + +class SharedMemoryBasic; + +} + +namespace layers { + +struct ScrollableLayerGuid; +class CompositorParent; +class GestureEventListener; +class ContainerLayer; +class PCompositorParent; +class ViewTransform; +class APZCTreeManager; +class AsyncPanZoomAnimation; +class FlingAnimation; + +/** + * 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; + typedef uint32_t TouchBehaviorFlags; + +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); + + // -------------------------------------------------------------------------- + // 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); + + /** + * 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 tag. + */ + void UpdateZoomConstraints(const ZoomConstraints& aConstraints); + + /** + * Return the zoom constraints last set for this APZC (in the constructor + * or in UpdateZoomConstraints()). + */ + ZoomConstraints GetZoomConstraints() const; + + /** + * 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); + + /** + * The platform implementation must set the cross process compositor if + * there is one associated with the layer tree. The cross process compositor + * allows the APZC to share its FrameMetrics with the content process. + * The shared FrameMetrics is used in progressive paint updates. + */ + void SetCrossProcessCompositorParent(PCompositorParent* aCrossProcessCompositorParent); + + // -------------------------------------------------------------------------- + // 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(); + + /** + * Returns the transform to take something from the coordinate space of the + * last thing we know gecko painted, to the coordinate space of the last thing + * we asked gecko to paint. In cases where that last request has not yet been + * processed, this is needed to transform input events properly into a space + * gecko will understand. + */ + gfx3DMatrix GetTransformToLastDispatchedPaint(); + + /** + * 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 LayerMargin CalculatePendingDisplayPort( + const FrameMetrics& aFrameMetrics, + const ScreenPoint& aVelocity, + 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); + + /** + * Handler for gesture events. + * Currently some gestures are detected in GestureEventListener that calls + * APZC back through this handler in order to avoid recursive calls to + * APZC::HandleInputEvent() which is supposed to do the work for + * ReceiveInputEvent(). + */ + nsEventStatus HandleGestureEvent(const InputData& aEvent); + + /** + * Populates the provided object (if non-null) with the scrollable guid of this apzc. + */ + void GetGuid(ScrollableLayerGuid* aGuidOut); + + /** + * Returns the scrollable guid of this apzc. + */ + ScrollableLayerGuid GetGuid(); + + /** + * 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); + + 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(); + + /** + * Take over a fling with the given velocity from another APZC. Used for + * during overscroll handoff for a fling. + */ + void TakeOverFling(ScreenPoint aVelocity); + + /** + * Returns allowed touch behavior for the given point on the scrollable layer. + * Internally performs a kind of hit testing based on the regions constructed + * on the main thread and attached to the current scrollable layer. Each of such regions + * contains info about allowed touch behavior. If regions info isn't enough it returns + * UNKNOWN value and we should switch to the fallback approach - asking content. + * TODO: for now it's only a stub and returns hardcoded magic value. As soon as bug 928833 + * is done we should integrate its logic here. + */ + TouchBehaviorFlags GetAllowedTouchBehavior(ScreenIntPoint& aPoint); + + /** + * Sets allowed touch behavior for current touch session. + * This method is invoked by the APZCTreeManager which in its turn invoked by + * the widget after performing touch-action values retrieving. + * Must be called after receiving the TOUCH_START even that started the + * touch session. + */ + void SetAllowedTouchBehavior(const nsTArray& aBehaviors); + + /** + * Returns whether this APZC is for an element marked with the 'scrollgrab' + * attribute. + */ + bool HasScrollgrab() const { return mFrameMetrics.mHasScrollgrab; } + + /** + * Set an extra offset for testing async scrolling. + */ + void SetTestAsyncScrollOffset(const CSSPoint& aPoint) + { + mTestAsyncScrollOffset = aPoint; + } + + /** + * Returns whether this APZC has room to be panned (in any direction). + */ + bool IsPannable() const; + +protected: + // Protected destructor, to discourage deletion outside of Release(): + ~AsyncPanZoomController(); + + /** + * 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 methods for long press gestures. + */ + nsEventStatus OnLongPress(const TapGestureInput& aEvent); + nsEventStatus OnLongPressUp(const TapGestureInput& aEvent); + + /** + * Helper method for single tap gestures. + */ + nsEventStatus OnSingleTapUp(const TapGestureInput& aEvent); + + /** + * Helper method for a single tap confirmed. + */ + nsEventStatus OnSingleTapConfirmed(const TapGestureInput& aEvent); + + /** + * Helper method for double taps. + */ + 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 ScreenPoint GetVelocityVector(); + + /** + * 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 the panning state basing on the pan direction angle and current touch-action value. + */ + void HandlePanningWithTouchAction(double angle, TouchBehaviorFlags value); + + /** + * Sets the panning state ignoring the touch action value. + */ + void HandlePanning(double angle); + + /** + * 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); + + /** + * 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 RequestContentRepaint(FrameMetrics& aFrameMetrics); + + /** + * Actually send the next pending paint request to gecko. + */ + void DispatchRepaintRequest(const 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(); + + /** + * Sets the timer for content response to a series of touch events, if it + * hasn't been already. This is to prevent us from batching up touch events + * indefinitely in the case that content doesn't respond with whether or not + * it wants to preventDefault. When the timer is fired, the touch event queue + * will be flushed. + */ + void SetContentResponseTimer(); + + /** + * Timeout function for content response. This should be called on a timer + * after we get our first touch event in a batch, under the condition that we + * waiting for response from content. If a notification comes indicating whether or not + * content preventDefaulted a series of touch events and touch behavior values are + * set before the timeout, the timeout should be cancelled. + */ + void TimeoutContentResponse(); + + /** + * 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_CONTENT_RESPONSE, /* 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 and the allowed touch behavior + was not set yet. we still need to abort animations. */ + }; + + // State related to a single touch block. Does not persist across touch blocks. + struct TouchBlockState { + + TouchBlockState() + : mAllowedTouchBehaviorSet(false), + mPreventDefault(false), + mPreventDefaultSet(false), + mSingleTapOccurred(false) + {} + + // Values of allowed touch behavior for touch points of this touch block. + // Since there are maybe a few current active touch points per time (multitouch case) + // and each touch point should have its own value of allowed touch behavior- we're + // keeping an array of allowed touch behavior values, not the single value. + nsTArray mAllowedTouchBehaviors; + + // Specifies whether mAllowedTouchBehaviors is set for this touch events block. + bool mAllowedTouchBehaviorSet; + + // Flag used to specify that content prevented the default behavior of this + // touch events block. + bool mPreventDefault; + + // Specifies whether mPreventDefault property is set for this touch events block. + bool mPreventDefaultSet; + + // Specifies whether a single tap event was generated during this touch block. + bool mSingleTapOccurred; + }; + + /* + * Returns whether current touch behavior values allow pinch-zooming. + */ + bool TouchActionAllowPinchZoom(); + + /* + * Returns whether current touch behavior values allow double-tap-zooming. + */ + bool TouchActionAllowDoubleTapZoom(); + + /* + * Returns allowed touch behavior from the mAllowedTouchBehavior array. + * In case apzc didn't receive touch behavior values within the timeout + * it returns default value. + */ + TouchBehaviorFlags GetTouchBehavior(uint32_t touchIndex); + + /** + * To move from the WAITING_CONTENT_RESPONSE state to TOUCHING one we need two + * conditions set: get content listeners response (whether they called preventDefault) + * and get allowed touch behaviors. + * This method checks both conditions and changes (or not changes) state + * appropriately. + */ + void CheckContentResponse(); + + /** + * 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 CSSPoint relative + * to the parent document. This excludes the transient compositor transform. + * NOTE: This must be converted to CSSPoint relative to the child + * document before sending over IPC. + */ + bool ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* 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(); + + // Convert a point from local screen coordinates to parent layer coordinates. + // This is a common operation as inputs from the tree manager are in screen + // coordinates but the composition bounds is in parent layer coordinates. + ParentLayerPoint ToParentLayerCoords(const ScreenPoint& aPoint); + + // Update mFrameMetrics.mTransformScale. This should be called whenever + // our CSS transform or the non-transient part of our async transform + // changes, as it corresponds to the scale portion of those transforms. + void UpdateTransformScale(); + + // Helper function for OnSingleTapUp() and OnSingleTapConfirmed(). + nsEventStatus GenerateSingleTap(const ScreenIntPoint& aPoint, mozilla::Modifiers aModifiers); + + // Common processing at the end of a touch block. + void OnTouchEndOrCancel(); + + uint64_t mLayersId; + nsRefPtr mCompositorParent; + PCompositorParent* mCrossProcessCompositorParent; + 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 mGeckoContentController; + nsRefPtr mGestureEventListener; + Monitor mRefPtrMonitor; + + /* Utility functions that return a addrefed pointer to the corresponding fields. */ + already_AddRefed GetGeckoContentController(); + already_AddRefed 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. + // IMPORTANT: See the note about lock ordering at the top of APZCTreeManager.h. + // This is mutable to allow entering it from 'const' methods; doing otherwise + // would significantly limit what methods could be 'const'. + mutable ReentrantMonitor mMonitor; + + // Specifies whether we should use touch-action css property. Initialized from + // the preferences. This property (in comparison with the global one) simplifies + // testing apzc with (and without) touch-action property enabled concurrently + // (e.g. with the gtest framework). + bool mTouchActionPropertyEnabled; + +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; + // The last metrics that we actually sent to Gecko. This allows us to transform + // inputs into a coordinate space that Gecko knows about. This assumes the pipe + // through which input events and repaint requests are sent to Gecko operates + // in a FIFO manner. + FrameMetrics mLastDispatchedPaintMetrics; + + nsTArray mTouchQueue; + + CancelableTask* mContentResponseTimeoutTask; + + AxisX mX; + AxisY mY; + + // This flag is set to true when we are in a axis-locked pan as a result of + // the touch-action CSS property. + bool mPanDirRestricted; + + // 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. + ZoomConstraints mZoomConstraints; + + // 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). + ParentLayerPoint 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; + + // Stores information about the current touch block. + TouchBlockState mTouchBlockState; + + // Extra offset to add in SampleContentTransformForFrame for testing + CSSPoint mTestAsyncScrollOffset; + + RefPtr mAnimation; + + friend class Axis; + friend class FlingAnimation; + + + /* =================================================================== + * 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 mTreeManager; + + nsRefPtr mLastChild; + nsRefPtr mPrevSibling; + nsRefPtr mParent; + + + /* =================================================================== + * The functions and members in this section are used in building the + * scroll handoff chain, so that we can have seamless scrolling continue + * across APZC instances. + */ +public: + void SetScrollHandoffParentId(FrameMetrics::ViewID aScrollParentId) { + mScrollParentId = aScrollParentId; + } + + FrameMetrics::ViewID GetScrollHandoffParentId() const { + return mScrollParentId; + } + + /** + * 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); + + void FlushRepaintForOverscrollHandoff(); + +private: + FrameMetrics::ViewID mScrollParentId; + + /** + * 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); + + + /* =================================================================== + * 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 ParentLayerRect& aRect, const gfx3DMatrix& aTransformToLayer, + const gfx3DMatrix& aTransformForLayer) { + mVisibleRect = aRect; + mAncestorTransform = aTransformToLayer; + mCSSTransform = aTransformForLayer; + UpdateTransformScale(); + } + + gfx3DMatrix GetAncestorTransform() const { + return mAncestorTransform; + } + + gfx3DMatrix GetCSSTransform() const { + return mCSSTransform; + } + + bool VisibleRegionContains(const ParentLayerPoint& 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()). */ + ParentLayerRect 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; + + + /* =================================================================== + * The functions and members in this section are used for sharing the + * FrameMetrics across processes for the progressive tiling code. + */ +private: + /* Unique id assigned to each APZC. Used with ViewID to uniquely identify + * shared FrameMeterics used in progressive tile painting. */ + const uint32_t mAPZCId; + + ipc::SharedMemoryBasic* mSharedFrameMetricsBuffer; + CrossProcessMutex* mSharedLock; + /** + * Called when ever mFrameMetrics is updated so that if it is being + * shared with the content process the shared FrameMetrics may be updated. + */ + void UpdateSharedCompositorFrameMetrics(); + /** + * Create a shared memory buffer for containing the FrameMetrics and + * a CrossProcessMutex that may be shared with the content process + * for use in progressive tiled update calculations. + */ + void ShareCompositorFrameMetrics(); +}; + +class AsyncPanZoomAnimation { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomAnimation) + +public: + AsyncPanZoomAnimation(const TimeDuration& aRepaintInterval = + TimeDuration::Forever()) + : mRepaintInterval(aRepaintInterval) + { } + + virtual bool Sample(FrameMetrics& aFrameMetrics, + const TimeDuration& aDelta) = 0; + + /** + * Get the deferred tasks in |mDeferredTasks|. See |mDeferredTasks| + * for more information. + * Clears |mDeferredTasks|. + */ + Vector TakeDeferredTasks() { + Vector result; + mDeferredTasks.swap(result); + return result; + } + + /** + * 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; + +protected: + // Protected destructor, to discourage deletion outside of Release(): + virtual ~AsyncPanZoomAnimation() + { } + + /** + * Tasks scheduled for execution after the APZC's mMonitor is released. + * Derived classes can add tasks here in Sample(), and the APZC can call + * ExecuteDeferredTasks() to execute them. + */ + Vector mDeferredTasks; +}; + +} +} + +#endif // mozilla_layers_PanZoomController_h