OLD | NEW |
---|---|
(Empty) | |
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 "content/browser/android/overscroll_controller_android.h" | |
6 | |
7 #include "base/android/build_info.h" | |
8 #include "cc/layers/layer.h" | |
9 #include "cc/output/compositor_frame_metadata.h" | |
10 #include "content/browser/android/content_view_core_impl.h" | |
11 #include "content/browser/android/edge_effect.h" | |
12 #include "content/browser/android/edge_effect_l.h" | |
13 #include "content/common/input/did_overscroll_params.h" | |
14 #include "ui/base/android/window_android.h" | |
15 #include "ui/base/android/window_android_compositor.h" | |
16 | |
17 namespace content { | |
18 namespace { | |
19 | |
20 // Used for conditional creation of EdgeEffect types for the overscroll glow. | |
21 const int kAndroidLSDKVersion = 21; | |
22 | |
23 ui::SystemUIResourceManager* GetSystemUIResourceManager( | |
24 ContentViewCore* content_view_core) { | |
25 ui::WindowAndroid* window = content_view_core->GetWindowAndroid(); | |
26 DCHECK(window); | |
27 ui::WindowAndroidCompositor* compositor = window->GetCompositor(); | |
28 DCHECK(compositor); | |
29 return &compositor->GetSystemUIResourceManager(); | |
30 } | |
31 | |
32 scoped_ptr<EdgeEffectBase> CreateGlowEdgeEffect( | |
33 ui::SystemUIResourceManager* resource_manager, | |
34 float dpi_scale) { | |
35 DCHECK(resource_manager); | |
36 static bool use_l_flavoured_effect = | |
37 base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion; | |
38 if (use_l_flavoured_effect) | |
39 return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager)); | |
40 | |
41 return scoped_ptr<EdgeEffectBase>( | |
42 new EdgeEffect(resource_manager, dpi_scale)); | |
43 } | |
44 | |
45 } // namespace | |
46 | |
47 OverscrollControllerAndroid::OverscrollControllerAndroid( | |
48 ContentViewCoreImpl* content_view_core) | |
49 : WebContentsObserver(content_view_core->GetWebContents()), | |
50 content_view_core_(content_view_core), | |
51 enabled_(true), | |
52 glow_effect_(base::Bind(&CreateGlowEdgeEffect, | |
53 GetSystemUIResourceManager(content_view_core), | |
54 content_view_core->GetDpiScale())), | |
55 refresh_effect_(GetSystemUIResourceManager(content_view_core), this), | |
56 triggered_refresh_active_(false) { | |
57 } | |
58 | |
59 OverscrollControllerAndroid::~OverscrollControllerAndroid() { | |
60 } | |
61 | |
62 bool OverscrollControllerAndroid::WillHandleGestureEvent( | |
63 const blink::WebGestureEvent& event) { | |
64 if (!enabled_) | |
65 return false; | |
66 | |
67 bool handled = false; | |
68 bool maybe_needs_animate = false; | |
69 switch (event.type) { | |
70 case blink::WebInputEvent::GestureScrollBegin: | |
71 refresh_effect_.OnScrollBegin(); | |
72 break; | |
73 | |
74 case blink::WebInputEvent::GestureScrollUpdate: { | |
75 gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX, | |
76 event.data.scrollUpdate.deltaY); | |
77 scroll_delta.Scale(GetDpiScale()); | |
78 maybe_needs_animate = true; | |
79 handled = refresh_effect_.WillHandleScrollUpdate(scroll_delta); | |
80 } break; | |
81 | |
82 case blink::WebInputEvent::GestureScrollEnd: | |
83 refresh_effect_.OnScrollEnd(gfx::Vector2dF()); | |
84 maybe_needs_animate = true; | |
85 break; | |
86 | |
87 case blink::WebInputEvent::GestureFlingStart: { | |
88 gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX, | |
89 event.data.flingStart.velocityY); | |
90 scroll_velocity.Scale(GetDpiScale()); | |
91 refresh_effect_.OnScrollEnd(scroll_velocity); | |
92 if (refresh_effect_.IsActive()) { | |
93 // TODO(jdduke): Figure out a cleaner way of suppressing a fling. | |
aelias_OOO_until_Jul13
2014/10/30 03:53:21
What would happen if we just let flings always go
jdduke (slow)
2014/10/30 15:19:02
That's the behavior I had originally, and it's cer
| |
94 // It's important that the any downstream code sees a scroll-ending | |
95 // event (in this case GestureFlingStart) if it has seen a scroll begin. | |
96 // Thus, we cannot simply consume the fling. Changing the event type to | |
97 // a GestureScrollEnd might work in practice, but could lead to | |
98 // unexpected results. For now, simply truncate the fling velocity, but | |
99 // not to zero as downstream code may not expect a zero-velocity fling. | |
100 blink::WebGestureEvent& modified_event = | |
101 const_cast<blink::WebGestureEvent&>(event); | |
102 modified_event.data.flingStart.velocityX = .01f; | |
103 modified_event.data.flingStart.velocityY = .01f; | |
104 } | |
105 maybe_needs_animate = true; | |
106 } break; | |
107 | |
108 default: | |
109 break; | |
110 } | |
111 | |
112 if (maybe_needs_animate && refresh_effect_.IsActive()) | |
113 content_view_core_->SetNeedsAnimate(); | |
Ted C
2014/10/31 23:52:05
I wonder if we should just make GetRenderWidgetHos
jdduke (slow)
2014/11/06 00:10:37
Your call, don't have a strong opinion here. It's
Ted C
2014/11/06 19:25:40
I have a slight preference for exposing RWHVA. Ma
jdduke (slow)
2014/11/07 18:33:44
I did us all a favor and removed all of the Conten
| |
114 | |
115 return handled; | |
116 } | |
117 | |
118 void OverscrollControllerAndroid::OnGestureEventAck( | |
119 const blink::WebGestureEvent& event, | |
120 InputEventAckState ack_result) { | |
121 if (!enabled_) | |
122 return; | |
123 | |
124 if (event.type == blink::WebInputEvent::GestureScrollUpdate) { | |
125 bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED; | |
126 refresh_effect_.OnScrollUpdateAck(consumed); | |
127 } | |
128 } | |
129 | |
130 void OverscrollControllerAndroid::OnOverscrolled( | |
131 const DidOverscrollParams& params) { | |
132 if (!enabled_) | |
133 return; | |
134 | |
135 if (refresh_effect_.IsActive() || | |
136 refresh_effect_.IsPendingScrollUpdateAck()) { | |
137 // An active (or potentially active) refresh effect should always pre-empt | |
138 // the passive glow effect. | |
139 return; | |
140 } | |
141 | |
142 const float dpi_scale = GetDpiScale(); | |
143 if (glow_effect_.OnOverscrolled( | |
144 base::TimeTicks::Now(), | |
145 gfx::ScaleVector2d(params.accumulated_overscroll, dpi_scale), | |
146 gfx::ScaleVector2d(params.latest_overscroll_delta, dpi_scale), | |
147 gfx::ScaleVector2d(params.current_fling_velocity, dpi_scale), | |
148 gfx::ScaleVector2d( | |
149 params.causal_event_viewport_point.OffsetFromOrigin(), | |
150 dpi_scale))) { | |
151 content_view_core_->SetNeedsAnimate(); | |
152 } | |
153 } | |
154 | |
155 bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time) { | |
156 if (!enabled_) | |
157 return false; | |
158 | |
159 scoped_refptr<cc::Layer> parent = content_view_core_->GetLayer(); | |
160 bool needs_animate = refresh_effect_.Animate(current_time, parent.get()); | |
161 needs_animate |= glow_effect_.Animate(current_time, parent.get()); | |
162 return needs_animate; | |
163 } | |
164 | |
165 void OverscrollControllerAndroid::OnFrameMetadataUpdated( | |
166 const cc::CompositorFrameMetadata& frame_metadata) { | |
167 const float scale_factor = | |
168 frame_metadata.page_scale_factor * frame_metadata.device_scale_factor; | |
169 gfx::SizeF viewport_size = | |
170 gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor); | |
171 gfx::SizeF content_size = | |
172 gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor); | |
173 gfx::Vector2dF content_scroll_offset = | |
174 gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor); | |
175 | |
176 refresh_effect_.UpdateDisplay(viewport_size, content_scroll_offset); | |
177 glow_effect_.UpdateDisplay( | |
178 viewport_size, content_size, content_scroll_offset); | |
179 } | |
180 | |
181 void OverscrollControllerAndroid::Enable() { | |
182 enabled_ = true; | |
183 } | |
184 | |
185 void OverscrollControllerAndroid::Disable() { | |
186 if (!enabled_) | |
187 return; | |
188 enabled_ = false; | |
189 if (!enabled_) { | |
190 refresh_effect_.Reset(); | |
191 glow_effect_.Reset(); | |
192 } | |
193 } | |
194 | |
195 void OverscrollControllerAndroid::DidNavigateMainFrame( | |
196 const LoadCommittedDetails& details, | |
197 const FrameNavigateParams& params) { | |
198 // Once the main frame has navigated, there's little need to further animate | |
199 // the reload effect. Note that the effect will naturally time out should the | |
200 // reload be interruped for any reason. | |
201 triggered_refresh_active_ = false; | |
202 } | |
203 | |
204 void OverscrollControllerAndroid::TriggerRefresh() { | |
205 triggered_refresh_active_ = false; | |
206 WebContents* web_contents = content_view_core_->GetWebContents(); | |
207 if (web_contents) { | |
208 triggered_refresh_active_ = true; | |
209 web_contents->ReloadFocusedFrame(false); | |
210 } | |
211 } | |
212 | |
213 bool OverscrollControllerAndroid::IsTriggeredRefreshActive() const { | |
214 return triggered_refresh_active_; | |
215 } | |
216 | |
217 float OverscrollControllerAndroid::GetDpiScale() const { | |
218 return content_view_core_->GetDpiScale(); | |
219 } | |
220 | |
221 } // namespace content | |
OLD | NEW |