// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef UI_EVENTS_GESTURES_GESTURE_SEQUENCE_H_ #define UI_EVENTS_GESTURES_GESTURE_SEQUENCE_H_ #include "base/timer/timer.h" #include "ui/events/event_constants.h" #include "ui/events/gesture_event_details.h" #include "ui/events/gestures/gesture_point.h" #include "ui/events/gestures/gesture_recognizer.h" #include "ui/gfx/rect.h" namespace ui { class TouchEvent; class GestureEvent; // Gesture state. enum GestureState { GS_NO_GESTURE, GS_PENDING_SYNTHETIC_CLICK, // One finger is down: tap could occur, but scroll cannot until the number of // active touch points changes. GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, // One finger is down: no gestures can occur until the number of active touch // points changes. GS_SYNTHETIC_CLICK_ABORTED, GS_SCROLL, GS_PINCH, GS_PENDING_TWO_FINGER_TAP, GS_PENDING_TWO_FINGER_TAP_NO_PINCH, GS_PENDING_PINCH, GS_PENDING_PINCH_NO_PINCH, }; enum ScrollType { ST_FREE, ST_HORIZONTAL, ST_VERTICAL, }; enum IsFirstScroll { FS_FIRST_SCROLL, FS_NOT_FIRST_SCROLL, }; // Delegates dispatch of gesture events for which the GestureSequence does not // have enough context to dispatch itself. class EVENTS_EXPORT GestureSequenceDelegate { public: virtual void DispatchPostponedGestureEvent(GestureEvent* event) = 0; protected: virtual ~GestureSequenceDelegate() {} }; // A GestureSequence recognizes gestures from touch sequences. class EVENTS_EXPORT GestureSequence { public: // Maximum number of points in a single gesture. static const int kMaxGesturePoints = 12; explicit GestureSequence(GestureSequenceDelegate* delegate); virtual ~GestureSequence(); typedef GestureRecognizer::Gestures Gestures; // Invoked for each touch event that could contribute to the current gesture. // Returns list of zero or more GestureEvents identified after processing // TouchEvent. // Caller would be responsible for freeing up Gestures. virtual Gestures* ProcessTouchEventForGesture(const TouchEvent& event, EventResult status); const GesturePoint* points() const { return points_; } int point_count() const { return point_count_; } const gfx::PointF& last_touch_location() const { return last_touch_location_; } protected: virtual base::OneShotTimer<GestureSequence>* CreateTimer(); base::OneShotTimer<GestureSequence>* GetLongPressTimer(); base::OneShotTimer<GestureSequence>* GetShowPressTimer(); private: // Recreates the axis-aligned bounding box that contains all the touch-points // at their most recent position. void RecreateBoundingBox(); void ResetVelocities(); GesturePoint& GesturePointForEvent(const TouchEvent& event); // Do a linear scan through points_ to find the GesturePoint // with id |point_id|. GesturePoint* GetPointByPointId(int point_id); bool IsSecondTouchDownCloseEnoughForTwoFingerTap(); // Creates a gesture event with the specified parameters. The function // includes some common information (e.g. number of touch-points in the // gesture etc.) in the gesture event as well. GestureEvent* CreateGestureEvent(const GestureEventDetails& details, const gfx::PointF& location, int flags, base::Time timestamp, unsigned int touch_id_bitmask); // Functions to be called to add GestureEvents, after successful recognition. // Tap gestures. void AppendTapDownGestureEvent(const GesturePoint& point, Gestures* gestures); void PrependTapCancelGestureEvent(const GesturePoint& point, Gestures* gestures); void AppendBeginGestureEvent(const GesturePoint& point, Gestures* gestures); void AppendEndGestureEvent(const GesturePoint& point, Gestures* gestures); void AppendClickGestureEvent(const GesturePoint& point, int tap_count, Gestures* gestures); void AppendDoubleClickGestureEvent(const GesturePoint& point, Gestures* gestures); void AppendLongPressGestureEvent(); void AppendShowPressGestureEvent(); void AppendLongTapGestureEvent(const GesturePoint& point, Gestures* gestures); // Scroll gestures. void AppendScrollGestureBegin(const GesturePoint& point, const gfx::PointF& location, Gestures* gestures); void AppendScrollGestureEnd(const GesturePoint& point, const gfx::PointF& location, Gestures* gestures, float x_velocity, float y_velocity); void AppendScrollGestureUpdate(GesturePoint& point, Gestures* gestures, IsFirstScroll is_first_scroll); // Pinch gestures. void AppendPinchGestureBegin(const GesturePoint& p1, const GesturePoint& p2, Gestures* gestures); void AppendPinchGestureEnd(const GesturePoint& p1, const GesturePoint& p2, float scale, Gestures* gestures); void AppendPinchGestureUpdate(const GesturePoint& point, float scale, Gestures* gestures); void AppendSwipeGesture(const GesturePoint& point, int swipe_x, int swipe_y, Gestures* gestures); void AppendTwoFingerTapGestureEvent(Gestures* gestures); void set_state(const GestureState state) { state_ = state; } // Various GestureTransitionFunctions for a signature. // There is, 1:many mapping from GestureTransitionFunction to Signature // But a Signature have only one GestureTransitionFunction. bool Click(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); bool ScrollStart(const TouchEvent& event, GesturePoint& point, Gestures* gestures); void BreakRailScroll(const TouchEvent& event, GesturePoint& point, Gestures* gestures); bool ScrollUpdate(const TouchEvent& event, GesturePoint& point, Gestures* gestures, IsFirstScroll is_first_scroll); bool TouchDown(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); bool TwoFingerTouchDown(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); bool TwoFingerTouchMove(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); bool TwoFingerTouchReleased(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); bool ScrollEnd(const TouchEvent& event, GesturePoint& point, Gestures* gestures); bool PinchStart(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); bool PinchUpdate(const TouchEvent& event, GesturePoint& point, Gestures* gestures); bool PinchEnd(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); bool MaybeSwipe(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); void TwoFingerTapOrPinch(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); void StopTimersIfRequired(const TouchEvent& event); void StartRailFreeScroll(const GesturePoint& point, Gestures* gestures); // Current state of gesture recognizer. GestureState state_; // ui::EventFlags. int flags_; // We maintain the smallest axis-aligned rectangle that contains all the // current touch-points. This box is updated after every touch-event. gfx::RectF bounding_box_; // The center of the bounding box used in the latest multi-finger scroll // update gesture. gfx::PointF latest_multi_scroll_update_location_; // The last scroll update prediction offset. This is removed from the scroll // distance on the next update since the page has already been scrolled this // distance. gfx::Vector2dF last_scroll_prediction_offset_; // For pinch, the 'distance' represents the diagonal distance of // |bounding_box_|. // The distance between the two points at PINCH_START. float pinch_distance_start_; // This distance is updated after each PINCH_UPDATE. float pinch_distance_current_; // This is the time when second touch down was received. Used for determining // if a two finger double tap has happened. base::TimeDelta second_touch_time_; ScrollType scroll_type_; scoped_ptr<base::OneShotTimer<GestureSequence> > long_press_timer_; scoped_ptr<base::OneShotTimer<GestureSequence> > show_press_timer_; GesturePoint points_[kMaxGesturePoints]; int point_count_; // Location of the last touch event. gfx::PointF last_touch_location_; GestureSequenceDelegate* delegate_; DISALLOW_COPY_AND_ASSIGN(GestureSequence); }; } // namespace ui #endif // UI_EVENTS_GESTURES_GESTURE_SEQUENCE_H_