Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / athena / wm / bezel_controller.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "athena/wm/bezel_controller.h"
6
7 #include "ui/aura/window.h"
8 #include "ui/events/event_handler.h"
9 #include "ui/gfx/display.h"
10 #include "ui/gfx/geometry/point_conversions.h"
11 #include "ui/gfx/screen.h"
12 #include "ui/wm/core/coordinate_conversion.h"
13
14 namespace athena {
15 namespace {
16
17 // Using bezel swipes, the first touch that is registered is usually within
18 // 5-10 pixels from the edge, but sometimes as far as 29 pixels away.
19 // So setting this width fairly high for now.
20 const float kBezelWidth = 20.0f;
21
22 const float kScrollDeltaNone = 0;
23
24 bool ShouldProcessGesture(ui::EventType event_type) {
25   return event_type == ui::ET_GESTURE_SCROLL_UPDATE ||
26          event_type == ui::ET_GESTURE_SCROLL_BEGIN ||
27          event_type == ui::ET_GESTURE_BEGIN ||
28          event_type == ui::ET_GESTURE_END;
29 }
30
31 gfx::Display GetDisplay(aura::Window* window) {
32   gfx::Screen* screen = gfx::Screen::GetScreenFor(window);
33   return screen->GetDisplayNearestWindow(window);
34 }
35
36 float GetDistance(const gfx::PointF& location,
37                   aura::Window* window,
38                   BezelController::Bezel bezel) {
39   DCHECK(bezel == BezelController::BEZEL_LEFT ||
40          bezel == BezelController::BEZEL_RIGHT);
41   // Convert location from window coordinates to screen coordinates.
42   gfx::Point point_in_screen(gfx::ToRoundedPoint(location));
43   wm::ConvertPointToScreen(window, &point_in_screen);
44   return bezel == BezelController::BEZEL_LEFT
45              ? point_in_screen.x()
46              : point_in_screen.x() - GetDisplay(window).bounds().width();
47 }
48
49 // Returns the bezel corresponding to the |location| in |window| or BEZEL_NONE
50 // if the location is outside of the bezel area.
51 // Only implemented for LEFT and RIGHT bezels.
52 BezelController::Bezel GetBezel(const gfx::PointF& location,
53                                 aura::Window* window) {
54   int screen_width = GetDisplay(window).bounds().width();
55   gfx::Point point_in_screen(gfx::ToRoundedPoint(location));
56   wm::ConvertPointToScreen(window, &point_in_screen);
57   if (point_in_screen.x() < kBezelWidth)
58     return BezelController::BEZEL_LEFT;
59   if (point_in_screen.x() > screen_width - kBezelWidth)
60     return BezelController::BEZEL_RIGHT;
61   return BezelController::BEZEL_NONE;
62 }
63
64 }  // namespace
65
66 BezelController::BezelController(aura::Window* container)
67     : container_(container),
68       state_(NONE),
69       scroll_bezel_(BEZEL_NONE),
70       scroll_target_(NULL),
71       left_right_delegate_(NULL) {
72 }
73
74 void BezelController::SetState(BezelController::State state) {
75   // Use SetState(State, float) if |state| is one of the BEZEL_SCROLLING states.
76   DCHECK_NE(state, BEZEL_SCROLLING_TWO_FINGERS);
77   DCHECK_NE(state, BEZEL_SCROLLING_ONE_FINGER);
78   SetState(state, kScrollDeltaNone);
79 }
80
81 void BezelController::SetState(BezelController::State state,
82                                float scroll_delta) {
83   if (!left_right_delegate_ || state == state_)
84     return;
85
86   State old_state = state_;
87   state_ = state;
88
89   if (state == NONE) {
90     scroll_bezel_ = BEZEL_NONE;
91     scroll_target_ = NULL;
92   }
93
94   if (state == BEZEL_SCROLLING_TWO_FINGERS) {
95     left_right_delegate_->BezelScrollBegin(scroll_bezel_, scroll_delta);
96   } else if (old_state == BEZEL_SCROLLING_TWO_FINGERS) {
97     // If BezelScrollEnd() hides |scroll_target_|, ET_GESTURE_END is dispatched
98     // and we get a reentrant call to SetState().
99     left_right_delegate_->BezelScrollEnd();
100   }
101 }
102
103 void BezelController::OnGestureEvent(ui::GestureEvent* event) {
104   // TODO(mfomitchev): Currently we aren't retargetting or consuming any of the
105   // touch events. This means that content can prevent the generation of gesture
106   // events and two-finger scroll won't work. Possible solution to this problem
107   // is hosting our own gesture recognizer or retargetting touch events at the
108   // bezel.
109
110   if (!left_right_delegate_)
111     return;
112
113   ui::EventType type = event->type();
114   if (!ShouldProcessGesture(type))
115     return;
116
117   const ui::GestureEventDetails& event_details = event->details();
118   int num_touch_points = event_details.touch_points();
119   if (num_touch_points == 1 && type == ui::ET_GESTURE_BEGIN) {
120     // Reset the state when the first finger touches and starts a gesture.
121     // Normally, the state gets reset when the last finger is lifted and we
122     // receive ET_GESTURE_END. However ET_GESTURE_END doesn't always get
123     // dispatched. (E.g. if the gesture target was hidden or deleted).
124     // Since we can't rely on receiving ET_GESTURE_END when the last finger is
125     // lifted, we also reset the state on ET_GESTURE_BEGIN when the first
126     // finger touches the screen.
127     SetState(NONE);
128   }
129
130   if (scroll_target_ && event->target() != scroll_target_)
131     return;
132
133   const gfx::PointF& event_location = event->location_f();
134   float scroll_delta = kScrollDeltaNone;
135   aura::Window* target_window = static_cast<aura::Window*>(event->target());
136   if (scroll_bezel_ != BEZEL_NONE)
137     scroll_delta = GetDistance(event_location, target_window, scroll_bezel_);
138
139   if (type == ui::ET_GESTURE_BEGIN) {
140     if (num_touch_points > 2) {
141       SetState(IGNORE_CURRENT_SCROLL);
142       return;
143     }
144     BezelController::Bezel event_bezel =
145         GetBezel(event->location_f(), target_window);
146     switch (state_) {
147       case NONE:
148         scroll_bezel_ = event_bezel;
149         scroll_target_ = event->target();
150         if (event_bezel != BEZEL_LEFT && event_bezel != BEZEL_RIGHT)
151           SetState(IGNORE_CURRENT_SCROLL);
152         else
153           SetState(BEZEL_GESTURE_STARTED);
154         break;
155       case IGNORE_CURRENT_SCROLL:
156         break;
157       case BEZEL_GESTURE_STARTED:
158       case BEZEL_SCROLLING_ONE_FINGER:
159         DCHECK_EQ(num_touch_points, 2);
160         DCHECK(scroll_target_);
161         DCHECK_NE(scroll_bezel_, BEZEL_NONE);
162
163         if (event_bezel != scroll_bezel_) {
164           SetState(IGNORE_CURRENT_SCROLL);
165           return;
166         }
167         if (state_ == BEZEL_SCROLLING_ONE_FINGER)
168           SetState(BEZEL_SCROLLING_TWO_FINGERS);
169         break;
170       case BEZEL_SCROLLING_TWO_FINGERS:
171         // Should've exited above
172         NOTREACHED();
173         break;
174     }
175   } else if (type == ui::ET_GESTURE_END) {
176     if (state_ == NONE)
177       return;
178
179     CHECK(scroll_target_);
180     if (num_touch_points == 1) {
181       SetState(NONE);
182     } else {
183       SetState(IGNORE_CURRENT_SCROLL);
184     }
185   } else if (type == ui::ET_GESTURE_SCROLL_BEGIN) {
186     DCHECK(state_ == IGNORE_CURRENT_SCROLL || state_ == BEZEL_GESTURE_STARTED);
187     if (state_ != BEZEL_GESTURE_STARTED)
188       return;
189
190     if (num_touch_points == 1) {
191       SetState(BEZEL_SCROLLING_ONE_FINGER, scroll_delta);
192       return;
193     }
194
195     DCHECK_EQ(num_touch_points, 2);
196     SetState(BEZEL_SCROLLING_TWO_FINGERS, scroll_delta);
197     if (left_right_delegate_->BezelCanScroll())
198       event->SetHandled();
199   } else if (type == ui::ET_GESTURE_SCROLL_UPDATE) {
200     if (state_ != BEZEL_SCROLLING_TWO_FINGERS)
201       return;
202
203     left_right_delegate_->BezelScrollUpdate(scroll_delta);
204     if (left_right_delegate_->BezelCanScroll())
205       event->SetHandled();
206   }
207 }
208
209 }  // namespace athena