Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / events / gesture_detection / snap_scroll_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 "ui/events/gesture_detection/snap_scroll_controller.h"
6
7 #include <cmath>
8
9 #include "ui/events/gesture_detection/motion_event.h"
10
11 namespace ui {
12 namespace {
13
14 // Minimum ratio between initial X and Y motion to allow snapping.
15 const float kMinSnapRatio = 1.25f;
16
17 // Size of the snap rail relative to the initial snap bound threshold.
18 const float kSnapBoundToChannelMultiplier = 1.5f;
19
20 float CalculateChannelDistance(float snap_bound,
21                                const gfx::SizeF& display_size) {
22   const float kMinChannelDistance = snap_bound * kSnapBoundToChannelMultiplier;
23   const float kMaxChannelDistance = kMinChannelDistance * 3.f;
24   const float kSnapChannelDipsPerScreenDip = kMinChannelDistance / 480.f;
25   if (display_size.IsEmpty())
26     return kMinChannelDistance;
27
28   float screen_size =
29       std::abs(hypot(static_cast<float>(display_size.width()),
30                      static_cast<float>(display_size.height())));
31
32   float snap_channel_distance = screen_size * kSnapChannelDipsPerScreenDip;
33   return std::max(kMinChannelDistance,
34                   std::min(kMaxChannelDistance, snap_channel_distance));
35 }
36
37 }  // namespace
38
39 SnapScrollController::SnapScrollController(float snap_bound,
40                                            const gfx::SizeF& display_size)
41     : snap_bound_(snap_bound),
42       channel_distance_(CalculateChannelDistance(snap_bound, display_size)),
43       mode_(SNAP_NONE) {
44 }
45
46 SnapScrollController::~SnapScrollController() {
47 }
48
49 void SnapScrollController::SetSnapScrollMode(
50     const MotionEvent& event,
51     bool is_scale_gesture_detection_in_progress) {
52   switch (event.GetAction()) {
53     case MotionEvent::ACTION_DOWN:
54       mode_ = SNAP_PENDING;
55       down_position_.set_x(event.GetX());
56       down_position_.set_y(event.GetY());
57       break;
58     case MotionEvent::ACTION_MOVE: {
59       if (is_scale_gesture_detection_in_progress)
60         break;
61
62       if (mode_ != SNAP_PENDING)
63         break;
64
65       // Set scrolling mode to SNAP_X if scroll exceeds |snap_bound_| and the
66       // ratio of x movement to y movement is sufficiently large. Similarly for
67       // SNAP_Y and y movement.
68       float dx = std::abs(event.GetX() - down_position_.x());
69       float dy = std::abs(event.GetY() - down_position_.y());
70       float kMinSnapBound = snap_bound_;
71       float kMaxSnapBound = snap_bound_ * 2.f;
72       if (dx * dx + dy * dy > kMinSnapBound * kMinSnapBound) {
73         if (!dy || (dx / dy > kMinSnapRatio && dy < kMaxSnapBound))
74           mode_ = SNAP_HORIZ;
75         else if (!dx || (dy / dx > kMinSnapRatio && dx < kMaxSnapBound))
76           mode_ = SNAP_VERT;
77       }
78
79       if (mode_ == SNAP_PENDING && dx > kMaxSnapBound && dy > kMaxSnapBound)
80         mode_ = SNAP_NONE;
81     } break;
82     case MotionEvent::ACTION_UP:
83     case MotionEvent::ACTION_CANCEL:
84       down_position_ = gfx::PointF();
85       accumulated_distance_ = gfx::Vector2dF();
86       break;
87     default:
88       break;
89   }
90 }
91
92 void SnapScrollController::UpdateSnapScrollMode(float distance_x,
93                                                 float distance_y) {
94   if (!IsSnappingScrolls())
95     return;
96
97   accumulated_distance_ +=
98       gfx::Vector2dF(std::abs(distance_x), std::abs(distance_y));
99   if (mode_ == SNAP_HORIZ) {
100     if (accumulated_distance_.y() > channel_distance_)
101       mode_ = SNAP_NONE;
102     else if (accumulated_distance_.x() > channel_distance_)
103       accumulated_distance_ = gfx::Vector2dF();
104   } else if (mode_ == SNAP_VERT) {
105     if (accumulated_distance_.x() > channel_distance_)
106       mode_ = SNAP_NONE;
107     else if (accumulated_distance_.y() > channel_distance_)
108       accumulated_distance_ = gfx::Vector2dF();
109   }
110 }
111
112 bool SnapScrollController::IsSnapVertical() const {
113   return mode_ == SNAP_VERT;
114 }
115
116 bool SnapScrollController::IsSnapHorizontal() const {
117   return mode_ == SNAP_HORIZ;
118 }
119
120 bool SnapScrollController::IsSnappingScrolls() const {
121   return IsSnapHorizontal() || IsSnapVertical();
122 }
123
124 }  // namespace ui