| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/events/blink/input_handler_proxy.h" | 5 #include "ui/events/blink/input_handler_proxy.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 | 75 |
| 76 double InSecondsF(const base::TimeTicks& time) { | 76 double InSecondsF(const base::TimeTicks& time) { |
| 77 return (time - base::TimeTicks()).InSecondsF(); | 77 return (time - base::TimeTicks()).InSecondsF(); |
| 78 } | 78 } |
| 79 | 79 |
| 80 bool ShouldSuppressScrollForFlingBoosting( | 80 bool ShouldSuppressScrollForFlingBoosting( |
| 81 const gfx::Vector2dF& current_fling_velocity, | 81 const gfx::Vector2dF& current_fling_velocity, |
| 82 const WebGestureEvent& scroll_update_event, | 82 const WebGestureEvent& scroll_update_event, |
| 83 double time_since_last_boost_event, | 83 double time_since_last_boost_event, |
| 84 double time_since_last_fling_animate) { | 84 double time_since_last_fling_animate) { |
| 85 DCHECK_EQ(WebInputEvent::GestureScrollUpdate, scroll_update_event.type); | 85 DCHECK_EQ(WebInputEvent::GestureScrollUpdate, scroll_update_event.type()); |
| 86 | 86 |
| 87 gfx::Vector2dF dx(scroll_update_event.data.scrollUpdate.deltaX, | 87 gfx::Vector2dF dx(scroll_update_event.data.scrollUpdate.deltaX, |
| 88 scroll_update_event.data.scrollUpdate.deltaY); | 88 scroll_update_event.data.scrollUpdate.deltaY); |
| 89 if (gfx::DotProduct(current_fling_velocity, dx) <= 0) | 89 if (gfx::DotProduct(current_fling_velocity, dx) <= 0) |
| 90 return false; | 90 return false; |
| 91 | 91 |
| 92 if (time_since_last_fling_animate > kFlingBoostTimeoutDelaySeconds) | 92 if (time_since_last_fling_animate > kFlingBoostTimeoutDelaySeconds) |
| 93 return false; | 93 return false; |
| 94 | 94 |
| 95 if (time_since_last_boost_event < 0.001) | 95 if (time_since_last_boost_event < 0.001) |
| 96 return true; | 96 return true; |
| 97 | 97 |
| 98 // TODO(jdduke): Use |scroll_update_event.data.scrollUpdate.velocity{X,Y}|. | 98 // TODO(jdduke): Use |scroll_update_event.data.scrollUpdate.velocity{X,Y}|. |
| 99 // The scroll must be of sufficient velocity to maintain the active fling. | 99 // The scroll must be of sufficient velocity to maintain the active fling. |
| 100 const gfx::Vector2dF scroll_velocity = | 100 const gfx::Vector2dF scroll_velocity = |
| 101 gfx::ScaleVector2d(dx, 1. / time_since_last_boost_event); | 101 gfx::ScaleVector2d(dx, 1. / time_since_last_boost_event); |
| 102 if (scroll_velocity.LengthSquared() < kMinBoostTouchScrollSpeedSquare) | 102 if (scroll_velocity.LengthSquared() < kMinBoostTouchScrollSpeedSquare) |
| 103 return false; | 103 return false; |
| 104 | 104 |
| 105 return true; | 105 return true; |
| 106 } | 106 } |
| 107 | 107 |
| 108 bool ShouldBoostFling(const gfx::Vector2dF& current_fling_velocity, | 108 bool ShouldBoostFling(const gfx::Vector2dF& current_fling_velocity, |
| 109 const WebGestureEvent& fling_start_event) { | 109 const WebGestureEvent& fling_start_event) { |
| 110 DCHECK_EQ(WebInputEvent::GestureFlingStart, fling_start_event.type); | 110 DCHECK_EQ(WebInputEvent::GestureFlingStart, fling_start_event.type()); |
| 111 | 111 |
| 112 gfx::Vector2dF new_fling_velocity( | 112 gfx::Vector2dF new_fling_velocity( |
| 113 fling_start_event.data.flingStart.velocityX, | 113 fling_start_event.data.flingStart.velocityX, |
| 114 fling_start_event.data.flingStart.velocityY); | 114 fling_start_event.data.flingStart.velocityY); |
| 115 | 115 |
| 116 if (gfx::DotProduct(current_fling_velocity, new_fling_velocity) <= 0) | 116 if (gfx::DotProduct(current_fling_velocity, new_fling_velocity) <= 0) |
| 117 return false; | 117 return false; |
| 118 | 118 |
| 119 if (current_fling_velocity.LengthSquared() < kMinBoostFlingSpeedSquare) | 119 if (current_fling_velocity.LengthSquared() < kMinBoostFlingSpeedSquare) |
| 120 return false; | 120 return false; |
| 121 | 121 |
| 122 if (new_fling_velocity.LengthSquared() < kMinBoostFlingSpeedSquare) | 122 if (new_fling_velocity.LengthSquared() < kMinBoostFlingSpeedSquare) |
| 123 return false; | 123 return false; |
| 124 | 124 |
| 125 return true; | 125 return true; |
| 126 } | 126 } |
| 127 | 127 |
| 128 WebGestureEvent ObtainGestureScrollBegin(const WebGestureEvent& event) { | 128 WebGestureEvent ObtainGestureScrollBegin(const WebGestureEvent& event) { |
| 129 WebGestureEvent scroll_begin_event = event; | 129 WebGestureEvent scroll_begin_event = event; |
| 130 scroll_begin_event.setType(WebInputEvent::GestureScrollBegin); | 130 scroll_begin_event.setType(WebInputEvent::GestureScrollBegin); |
| 131 scroll_begin_event.data.scrollBegin.deltaXHint = 0; | 131 scroll_begin_event.data.scrollBegin.deltaXHint = 0; |
| 132 scroll_begin_event.data.scrollBegin.deltaYHint = 0; | 132 scroll_begin_event.data.scrollBegin.deltaYHint = 0; |
| 133 return scroll_begin_event; | 133 return scroll_begin_event; |
| 134 } | 134 } |
| 135 | 135 |
| 136 cc::ScrollState CreateScrollStateForGesture(const WebGestureEvent& event) { | 136 cc::ScrollState CreateScrollStateForGesture(const WebGestureEvent& event) { |
| 137 cc::ScrollStateData scroll_state_data; | 137 cc::ScrollStateData scroll_state_data; |
| 138 switch (event.type) { | 138 switch (event.type()) { |
| 139 case WebInputEvent::GestureScrollBegin: | 139 case WebInputEvent::GestureScrollBegin: |
| 140 scroll_state_data.position_x = event.x; | 140 scroll_state_data.position_x = event.x; |
| 141 scroll_state_data.position_y = event.y; | 141 scroll_state_data.position_y = event.y; |
| 142 scroll_state_data.is_beginning = true; | 142 scroll_state_data.is_beginning = true; |
| 143 break; | 143 break; |
| 144 case WebInputEvent::GestureFlingStart: | 144 case WebInputEvent::GestureFlingStart: |
| 145 scroll_state_data.velocity_x = event.data.flingStart.velocityX; | 145 scroll_state_data.velocity_x = event.data.flingStart.velocityX; |
| 146 scroll_state_data.velocity_y = event.data.flingStart.velocityY; | 146 scroll_state_data.velocity_y = event.data.flingStart.velocityY; |
| 147 scroll_state_data.is_in_inertial_phase = true; | 147 scroll_state_data.is_in_inertial_phase = true; |
| 148 break; | 148 break; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 161 break; | 161 break; |
| 162 default: | 162 default: |
| 163 NOTREACHED(); | 163 NOTREACHED(); |
| 164 break; | 164 break; |
| 165 } | 165 } |
| 166 return cc::ScrollState(scroll_state_data); | 166 return cc::ScrollState(scroll_state_data); |
| 167 } | 167 } |
| 168 | 168 |
| 169 void ReportInputEventLatencyUma(const WebInputEvent& event, | 169 void ReportInputEventLatencyUma(const WebInputEvent& event, |
| 170 const ui::LatencyInfo& latency_info) { | 170 const ui::LatencyInfo& latency_info) { |
| 171 if (!(event.type == WebInputEvent::GestureScrollBegin || | 171 if (!(event.type() == WebInputEvent::GestureScrollBegin || |
| 172 event.type == WebInputEvent::GestureScrollUpdate || | 172 event.type() == WebInputEvent::GestureScrollUpdate || |
| 173 event.type == WebInputEvent::GesturePinchBegin || | 173 event.type() == WebInputEvent::GesturePinchBegin || |
| 174 event.type == WebInputEvent::GesturePinchUpdate || | 174 event.type() == WebInputEvent::GesturePinchUpdate || |
| 175 event.type == WebInputEvent::GestureFlingStart)) { | 175 event.type() == WebInputEvent::GestureFlingStart)) { |
| 176 return; | 176 return; |
| 177 } | 177 } |
| 178 | 178 |
| 179 ui::LatencyInfo::LatencyMap::const_iterator it = | 179 ui::LatencyInfo::LatencyMap::const_iterator it = |
| 180 latency_info.latency_components().find(std::make_pair( | 180 latency_info.latency_components().find(std::make_pair( |
| 181 ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0)); | 181 ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0)); |
| 182 | 182 |
| 183 if (it == latency_info.latency_components().end()) | 183 if (it == latency_info.latency_components().end()) |
| 184 return; | 184 return; |
| 185 | 185 |
| 186 base::TimeDelta delta = base::TimeTicks::Now() - it->second.event_time; | 186 base::TimeDelta delta = base::TimeTicks::Now() - it->second.event_time; |
| 187 for (size_t i = 0; i < it->second.event_count; ++i) { | 187 for (size_t i = 0; i < it->second.event_count; ++i) { |
| 188 switch (event.type) { | 188 switch (event.type()) { |
| 189 case blink::WebInputEvent::GestureScrollBegin: | 189 case blink::WebInputEvent::GestureScrollBegin: |
| 190 UMA_HISTOGRAM_CUSTOM_COUNTS( | 190 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 191 "Event.Latency.RendererImpl.GestureScrollBegin", | 191 "Event.Latency.RendererImpl.GestureScrollBegin", |
| 192 delta.InMicroseconds(), 1, 1000000, 100); | 192 delta.InMicroseconds(), 1, 1000000, 100); |
| 193 break; | 193 break; |
| 194 case blink::WebInputEvent::GestureScrollUpdate: | 194 case blink::WebInputEvent::GestureScrollUpdate: |
| 195 UMA_HISTOGRAM_CUSTOM_COUNTS( | 195 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 196 // So named for historical reasons. | 196 // So named for historical reasons. |
| 197 "Event.Latency.RendererImpl.GestureScroll2", | 197 "Event.Latency.RendererImpl.GestureScroll2", |
| 198 delta.InMicroseconds(), 1, 1000000, 100); | 198 delta.InMicroseconds(), 1, 1000000, 100); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, | 288 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, |
| 289 "step", "HandleInputEventImpl"); | 289 "step", "HandleInputEventImpl"); |
| 290 | 290 |
| 291 std::unique_ptr<EventWithCallback> event_with_callback = | 291 std::unique_ptr<EventWithCallback> event_with_callback = |
| 292 base::MakeUnique<EventWithCallback>(std::move(event), latency_info, | 292 base::MakeUnique<EventWithCallback>(std::move(event), latency_info, |
| 293 tick_clock_->NowTicks(), callback); | 293 tick_clock_->NowTicks(), callback); |
| 294 | 294 |
| 295 // Note: Other input can race ahead of gesture input as they don't have to go | 295 // Note: Other input can race ahead of gesture input as they don't have to go |
| 296 // through the queue, but we believe it's OK to do so. | 296 // through the queue, but we believe it's OK to do so. |
| 297 if (!compositor_event_queue_ || | 297 if (!compositor_event_queue_ || |
| 298 !IsGestureScollOrPinch(event_with_callback->event().type)) { | 298 !IsGestureScollOrPinch(event_with_callback->event().type())) { |
| 299 DispatchSingleInputEvent(std::move(event_with_callback), | 299 DispatchSingleInputEvent(std::move(event_with_callback), |
| 300 tick_clock_->NowTicks()); | 300 tick_clock_->NowTicks()); |
| 301 return; | 301 return; |
| 302 } | 302 } |
| 303 | 303 |
| 304 if (has_ongoing_compositor_scroll_pinch_) { | 304 if (has_ongoing_compositor_scroll_pinch_) { |
| 305 bool needs_animate_input = compositor_event_queue_->empty(); | 305 bool needs_animate_input = compositor_event_queue_->empty(); |
| 306 compositor_event_queue_->Queue(std::move(event_with_callback), | 306 compositor_event_queue_->Queue(std::move(event_with_callback), |
| 307 tick_clock_->NowTicks()); | 307 tick_clock_->NowTicks()); |
| 308 if (needs_animate_input) | 308 if (needs_animate_input) |
| 309 input_handler_->SetNeedsAnimateInput(); | 309 input_handler_->SetNeedsAnimateInput(); |
| 310 return; | 310 return; |
| 311 } | 311 } |
| 312 | 312 |
| 313 // We have to dispatch the event to know whether the gesture sequence will be | 313 // We have to dispatch the event to know whether the gesture sequence will be |
| 314 // handled by the compositor or not. | 314 // handled by the compositor or not. |
| 315 DispatchSingleInputEvent(std::move(event_with_callback), | 315 DispatchSingleInputEvent(std::move(event_with_callback), |
| 316 tick_clock_->NowTicks()); | 316 tick_clock_->NowTicks()); |
| 317 } | 317 } |
| 318 | 318 |
| 319 void InputHandlerProxy::DispatchSingleInputEvent( | 319 void InputHandlerProxy::DispatchSingleInputEvent( |
| 320 std::unique_ptr<EventWithCallback> event_with_callback, | 320 std::unique_ptr<EventWithCallback> event_with_callback, |
| 321 const base::TimeTicks now) { | 321 const base::TimeTicks now) { |
| 322 if (compositor_event_queue_ && | 322 if (compositor_event_queue_ && |
| 323 IsGestureScollOrPinch(event_with_callback->event().type)) { | 323 IsGestureScollOrPinch(event_with_callback->event().type())) { |
| 324 // Report the coalesced count only for continuous events to avoid the noise | 324 // Report the coalesced count only for continuous events to avoid the noise |
| 325 // from non-continuous events. | 325 // from non-continuous events. |
| 326 if (IsContinuousGestureEvent(event_with_callback->event().type)) { | 326 if (IsContinuousGestureEvent(event_with_callback->event().type())) { |
| 327 UMA_HISTOGRAM_CUSTOM_COUNTS( | 327 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 328 "Event.CompositorThreadEventQueue.Continuous.HeadQueueingTime", | 328 "Event.CompositorThreadEventQueue.Continuous.HeadQueueingTime", |
| 329 (now - event_with_callback->creation_timestamp()).InMicroseconds(), 1, | 329 (now - event_with_callback->creation_timestamp()).InMicroseconds(), 1, |
| 330 kTenSeconds, 50); | 330 kTenSeconds, 50); |
| 331 | 331 |
| 332 UMA_HISTOGRAM_CUSTOM_COUNTS( | 332 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 333 "Event.CompositorThreadEventQueue.Continuous.TailQueueingTime", | 333 "Event.CompositorThreadEventQueue.Continuous.TailQueueingTime", |
| 334 (now - event_with_callback->last_coalesced_timestamp()) | 334 (now - event_with_callback->last_coalesced_timestamp()) |
| 335 .InMicroseconds(), | 335 .InMicroseconds(), |
| 336 1, kTenSeconds, 50); | 336 1, kTenSeconds, 50); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 348 | 348 |
| 349 ui::LatencyInfo monitored_latency_info = event_with_callback->latency_info(); | 349 ui::LatencyInfo monitored_latency_info = event_with_callback->latency_info(); |
| 350 std::unique_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor = | 350 std::unique_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor = |
| 351 input_handler_->CreateLatencyInfoSwapPromiseMonitor( | 351 input_handler_->CreateLatencyInfoSwapPromiseMonitor( |
| 352 &monitored_latency_info); | 352 &monitored_latency_info); |
| 353 | 353 |
| 354 current_overscroll_params_.reset(); | 354 current_overscroll_params_.reset(); |
| 355 InputHandlerProxy::EventDisposition disposition = | 355 InputHandlerProxy::EventDisposition disposition = |
| 356 HandleInputEvent(event_with_callback->event()); | 356 HandleInputEvent(event_with_callback->event()); |
| 357 | 357 |
| 358 switch (event_with_callback->event().type) { | 358 switch (event_with_callback->event().type()) { |
| 359 case blink::WebGestureEvent::GestureScrollBegin: | 359 case blink::WebGestureEvent::GestureScrollBegin: |
| 360 case blink::WebGestureEvent::GesturePinchBegin: | 360 case blink::WebGestureEvent::GesturePinchBegin: |
| 361 case blink::WebGestureEvent::GestureScrollUpdate: | 361 case blink::WebGestureEvent::GestureScrollUpdate: |
| 362 case blink::WebGestureEvent::GesturePinchUpdate: | 362 case blink::WebGestureEvent::GesturePinchUpdate: |
| 363 has_ongoing_compositor_scroll_pinch_ = disposition == DID_HANDLE; | 363 has_ongoing_compositor_scroll_pinch_ = disposition == DID_HANDLE; |
| 364 break; | 364 break; |
| 365 | 365 |
| 366 case blink::WebGestureEvent::GestureScrollEnd: | 366 case blink::WebGestureEvent::GestureScrollEnd: |
| 367 case blink::WebGestureEvent::GesturePinchEnd: | 367 case blink::WebGestureEvent::GesturePinchEnd: |
| 368 has_ongoing_compositor_scroll_pinch_ = false; | 368 has_ongoing_compositor_scroll_pinch_ = false; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 386 DispatchSingleInputEvent(compositor_event_queue_->Pop(), now); | 386 DispatchSingleInputEvent(compositor_event_queue_->Pop(), now); |
| 387 } | 387 } |
| 388 | 388 |
| 389 InputHandlerProxy::EventDisposition InputHandlerProxy::HandleInputEvent( | 389 InputHandlerProxy::EventDisposition InputHandlerProxy::HandleInputEvent( |
| 390 const WebInputEvent& event) { | 390 const WebInputEvent& event) { |
| 391 DCHECK(input_handler_); | 391 DCHECK(input_handler_); |
| 392 | 392 |
| 393 if (FilterInputEventForFlingBoosting(event)) | 393 if (FilterInputEventForFlingBoosting(event)) |
| 394 return DID_HANDLE; | 394 return DID_HANDLE; |
| 395 | 395 |
| 396 switch (event.type) { | 396 switch (event.type()) { |
| 397 case WebInputEvent::MouseWheel: | 397 case WebInputEvent::MouseWheel: |
| 398 return HandleMouseWheel(static_cast<const WebMouseWheelEvent&>(event)); | 398 return HandleMouseWheel(static_cast<const WebMouseWheelEvent&>(event)); |
| 399 | 399 |
| 400 case WebInputEvent::GestureScrollBegin: | 400 case WebInputEvent::GestureScrollBegin: |
| 401 return HandleGestureScrollBegin( | 401 return HandleGestureScrollBegin( |
| 402 static_cast<const WebGestureEvent&>(event)); | 402 static_cast<const WebGestureEvent&>(event)); |
| 403 | 403 |
| 404 case WebInputEvent::GestureScrollUpdate: | 404 case WebInputEvent::GestureScrollUpdate: |
| 405 return HandleGestureScrollUpdate( | 405 return HandleGestureScrollUpdate( |
| 406 static_cast<const WebGestureEvent&>(event)); | 406 static_cast<const WebGestureEvent&>(event)); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y)); | 499 input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y)); |
| 500 return DID_NOT_HANDLE; | 500 return DID_NOT_HANDLE; |
| 501 } | 501 } |
| 502 case WebInputEvent::MouseLeave: { | 502 case WebInputEvent::MouseLeave: { |
| 503 CHECK(input_handler_); | 503 CHECK(input_handler_); |
| 504 input_handler_->MouseLeave(); | 504 input_handler_->MouseLeave(); |
| 505 return DID_NOT_HANDLE; | 505 return DID_NOT_HANDLE; |
| 506 } | 506 } |
| 507 | 507 |
| 508 default: | 508 default: |
| 509 if (WebInputEvent::isKeyboardEventType(event.type)) { | 509 if (WebInputEvent::isKeyboardEventType(event.type())) { |
| 510 // Only call |CancelCurrentFling()| if a fling was active, as it will | 510 // Only call |CancelCurrentFling()| if a fling was active, as it will |
| 511 // otherwise disrupt an in-progress touch scroll. | 511 // otherwise disrupt an in-progress touch scroll. |
| 512 if (fling_curve_) | 512 if (fling_curve_) |
| 513 CancelCurrentFling(); | 513 CancelCurrentFling(); |
| 514 } | 514 } |
| 515 break; | 515 break; |
| 516 } | 516 } |
| 517 | 517 |
| 518 return DID_NOT_HANDLE; | 518 return DID_NOT_HANDLE; |
| 519 } | 519 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 627 // TODO(jamesr): We don't properly handle scroll by page in the compositor | 627 // TODO(jamesr): We don't properly handle scroll by page in the compositor |
| 628 // thread, so punt it to the main thread. http://crbug.com/236639 | 628 // thread, so punt it to the main thread. http://crbug.com/236639 |
| 629 RecordMainThreadScrollingReasons( | 629 RecordMainThreadScrollingReasons( |
| 630 blink::WebGestureDeviceTouchpad, | 630 blink::WebGestureDeviceTouchpad, |
| 631 cc::MainThreadScrollingReason::kPageBasedScrolling); | 631 cc::MainThreadScrollingReason::kPageBasedScrolling); |
| 632 return DID_NOT_HANDLE; | 632 return DID_NOT_HANDLE; |
| 633 | 633 |
| 634 } else if (ShouldAnimate(wheel_event.hasPreciseScrollingDeltas)) { | 634 } else if (ShouldAnimate(wheel_event.hasPreciseScrollingDeltas)) { |
| 635 base::TimeTicks event_time = | 635 base::TimeTicks event_time = |
| 636 base::TimeTicks() + | 636 base::TimeTicks() + |
| 637 base::TimeDelta::FromSecondsD(wheel_event.timeStampSeconds); | 637 base::TimeDelta::FromSecondsD(wheel_event.timeStampSeconds()); |
| 638 base::TimeDelta delay = base::TimeTicks::Now() - event_time; | 638 base::TimeDelta delay = base::TimeTicks::Now() - event_time; |
| 639 cc::InputHandler::ScrollStatus scroll_status = | 639 cc::InputHandler::ScrollStatus scroll_status = |
| 640 input_handler_->ScrollAnimated(gfx::Point(wheel_event.x, wheel_event.y), | 640 input_handler_->ScrollAnimated(gfx::Point(wheel_event.x, wheel_event.y), |
| 641 scroll_delta, delay); | 641 scroll_delta, delay); |
| 642 | 642 |
| 643 RecordMainThreadScrollingReasons( | 643 RecordMainThreadScrollingReasons( |
| 644 blink::WebGestureDeviceTouchpad, | 644 blink::WebGestureDeviceTouchpad, |
| 645 scroll_status.main_thread_scrolling_reasons); | 645 scroll_status.main_thread_scrolling_reasons); |
| 646 | 646 |
| 647 switch (scroll_status.thread) { | 647 switch (scroll_status.thread) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 | 783 |
| 784 cc::ScrollState scroll_state = CreateScrollStateForGesture(gesture_event); | 784 cc::ScrollState scroll_state = CreateScrollStateForGesture(gesture_event); |
| 785 gfx::Point scroll_point(gesture_event.x, gesture_event.y); | 785 gfx::Point scroll_point(gesture_event.x, gesture_event.y); |
| 786 gfx::Vector2dF scroll_delta(-gesture_event.data.scrollUpdate.deltaX, | 786 gfx::Vector2dF scroll_delta(-gesture_event.data.scrollUpdate.deltaX, |
| 787 -gesture_event.data.scrollUpdate.deltaY); | 787 -gesture_event.data.scrollUpdate.deltaY); |
| 788 | 788 |
| 789 if (ShouldAnimate(gesture_event.data.scrollUpdate.deltaUnits != | 789 if (ShouldAnimate(gesture_event.data.scrollUpdate.deltaUnits != |
| 790 blink::WebGestureEvent::ScrollUnits::Pixels)) { | 790 blink::WebGestureEvent::ScrollUnits::Pixels)) { |
| 791 base::TimeTicks event_time = | 791 base::TimeTicks event_time = |
| 792 base::TimeTicks() + | 792 base::TimeTicks() + |
| 793 base::TimeDelta::FromSecondsD(gesture_event.timeStampSeconds); | 793 base::TimeDelta::FromSecondsD(gesture_event.timeStampSeconds()); |
| 794 base::TimeDelta delay = base::TimeTicks::Now() - event_time; | 794 base::TimeDelta delay = base::TimeTicks::Now() - event_time; |
| 795 switch (input_handler_->ScrollAnimated(scroll_point, scroll_delta, delay) | 795 switch (input_handler_->ScrollAnimated(scroll_point, scroll_delta, delay) |
| 796 .thread) { | 796 .thread) { |
| 797 case cc::InputHandler::SCROLL_ON_IMPL_THREAD: | 797 case cc::InputHandler::SCROLL_ON_IMPL_THREAD: |
| 798 return DID_HANDLE; | 798 return DID_HANDLE; |
| 799 case cc::InputHandler::SCROLL_IGNORED: | 799 case cc::InputHandler::SCROLL_IGNORED: |
| 800 return DROP_EVENT; | 800 return DROP_EVENT; |
| 801 default: | 801 default: |
| 802 return DID_NOT_HANDLE; | 802 return DID_NOT_HANDLE; |
| 803 } | 803 } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 887 WebFloatPoint(vx, vy), | 887 WebFloatPoint(vx, vy), |
| 888 blink::WebSize())); | 888 blink::WebSize())); |
| 889 disallow_horizontal_fling_scroll_ = !vx; | 889 disallow_horizontal_fling_scroll_ = !vx; |
| 890 disallow_vertical_fling_scroll_ = !vy; | 890 disallow_vertical_fling_scroll_ = !vy; |
| 891 TRACE_EVENT_ASYNC_BEGIN2("input,benchmark,rail", | 891 TRACE_EVENT_ASYNC_BEGIN2("input,benchmark,rail", |
| 892 "InputHandlerProxy::HandleGestureFling::started", | 892 "InputHandlerProxy::HandleGestureFling::started", |
| 893 this, "vx", vx, "vy", vy); | 893 this, "vx", vx, "vy", vy); |
| 894 // Note that the timestamp will only be used to kickstart the animation if | 894 // Note that the timestamp will only be used to kickstart the animation if |
| 895 // its sufficiently close to the timestamp of the first call |Animate()|. | 895 // its sufficiently close to the timestamp of the first call |Animate()|. |
| 896 has_fling_animation_started_ = false; | 896 has_fling_animation_started_ = false; |
| 897 fling_parameters_.startTime = gesture_event.timeStampSeconds; | 897 fling_parameters_.startTime = gesture_event.timeStampSeconds(); |
| 898 fling_parameters_.delta = WebFloatPoint(vx, vy); | 898 fling_parameters_.delta = WebFloatPoint(vx, vy); |
| 899 fling_parameters_.point = WebPoint(gesture_event.x, gesture_event.y); | 899 fling_parameters_.point = WebPoint(gesture_event.x, gesture_event.y); |
| 900 fling_parameters_.globalPoint = | 900 fling_parameters_.globalPoint = |
| 901 WebPoint(gesture_event.globalX, gesture_event.globalY); | 901 WebPoint(gesture_event.globalX, gesture_event.globalY); |
| 902 fling_parameters_.modifiers = gesture_event.modifiers; | 902 fling_parameters_.modifiers = gesture_event.modifiers(); |
| 903 fling_parameters_.sourceDevice = gesture_event.sourceDevice; | 903 fling_parameters_.sourceDevice = gesture_event.sourceDevice; |
| 904 RequestAnimation(); | 904 RequestAnimation(); |
| 905 return DID_HANDLE; | 905 return DID_HANDLE; |
| 906 } | 906 } |
| 907 case cc::InputHandler::SCROLL_UNKNOWN: | 907 case cc::InputHandler::SCROLL_UNKNOWN: |
| 908 case cc::InputHandler::SCROLL_ON_MAIN_THREAD: { | 908 case cc::InputHandler::SCROLL_ON_MAIN_THREAD: { |
| 909 TRACE_EVENT_INSTANT0("input,rail", | 909 TRACE_EVENT_INSTANT0("input,rail", |
| 910 "InputHandlerProxy::HandleGestureFling::" | 910 "InputHandlerProxy::HandleGestureFling::" |
| 911 "scroll_on_main_thread", | 911 "scroll_on_main_thread", |
| 912 TRACE_EVENT_SCOPE_THREAD); | 912 TRACE_EVENT_SCOPE_THREAD); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1015 | 1015 |
| 1016 InputHandlerProxy::EventDisposition InputHandlerProxy::HandleTouchEnd( | 1016 InputHandlerProxy::EventDisposition InputHandlerProxy::HandleTouchEnd( |
| 1017 const blink::WebTouchEvent& touch_event) { | 1017 const blink::WebTouchEvent& touch_event) { |
| 1018 if (touch_event.touchesLength == 1) | 1018 if (touch_event.touchesLength == 1) |
| 1019 touch_start_result_ = kEventDispositionUndefined; | 1019 touch_start_result_ = kEventDispositionUndefined; |
| 1020 return DID_NOT_HANDLE; | 1020 return DID_NOT_HANDLE; |
| 1021 } | 1021 } |
| 1022 | 1022 |
| 1023 bool InputHandlerProxy::FilterInputEventForFlingBoosting( | 1023 bool InputHandlerProxy::FilterInputEventForFlingBoosting( |
| 1024 const WebInputEvent& event) { | 1024 const WebInputEvent& event) { |
| 1025 if (!WebInputEvent::isGestureEventType(event.type)) | 1025 if (!WebInputEvent::isGestureEventType(event.type())) |
| 1026 return false; | 1026 return false; |
| 1027 | 1027 |
| 1028 if (!fling_curve_) { | 1028 if (!fling_curve_) { |
| 1029 DCHECK(!deferred_fling_cancel_time_seconds_); | 1029 DCHECK(!deferred_fling_cancel_time_seconds_); |
| 1030 return false; | 1030 return false; |
| 1031 } | 1031 } |
| 1032 | 1032 |
| 1033 const WebGestureEvent& gesture_event = | 1033 const WebGestureEvent& gesture_event = |
| 1034 static_cast<const WebGestureEvent&>(event); | 1034 static_cast<const WebGestureEvent&>(event); |
| 1035 if (gesture_event.type == WebInputEvent::GestureFlingCancel) { | 1035 if (gesture_event.type() == WebInputEvent::GestureFlingCancel) { |
| 1036 if (gesture_event.data.flingCancel.preventBoosting) | 1036 if (gesture_event.data.flingCancel.preventBoosting) |
| 1037 return false; | 1037 return false; |
| 1038 | 1038 |
| 1039 if (current_fling_velocity_.LengthSquared() < kMinBoostFlingSpeedSquare) | 1039 if (current_fling_velocity_.LengthSquared() < kMinBoostFlingSpeedSquare) |
| 1040 return false; | 1040 return false; |
| 1041 | 1041 |
| 1042 TRACE_EVENT_INSTANT0("input", | 1042 TRACE_EVENT_INSTANT0("input", |
| 1043 "InputHandlerProxy::FlingBoostStart", | 1043 "InputHandlerProxy::FlingBoostStart", |
| 1044 TRACE_EVENT_SCOPE_THREAD); | 1044 TRACE_EVENT_SCOPE_THREAD); |
| 1045 deferred_fling_cancel_time_seconds_ = | 1045 deferred_fling_cancel_time_seconds_ = |
| 1046 event.timeStampSeconds + kFlingBoostTimeoutDelaySeconds; | 1046 event.timeStampSeconds() + kFlingBoostTimeoutDelaySeconds; |
| 1047 return true; | 1047 return true; |
| 1048 } | 1048 } |
| 1049 | 1049 |
| 1050 // A fling is either inactive or is "free spinning", i.e., has yet to be | 1050 // A fling is either inactive or is "free spinning", i.e., has yet to be |
| 1051 // interrupted by a touch gesture, in which case there is nothing to filter. | 1051 // interrupted by a touch gesture, in which case there is nothing to filter. |
| 1052 if (!deferred_fling_cancel_time_seconds_) | 1052 if (!deferred_fling_cancel_time_seconds_) |
| 1053 return false; | 1053 return false; |
| 1054 | 1054 |
| 1055 // Gestures from a different source should immediately interrupt the fling. | 1055 // Gestures from a different source should immediately interrupt the fling. |
| 1056 if (gesture_event.sourceDevice != fling_parameters_.sourceDevice) { | 1056 if (gesture_event.sourceDevice != fling_parameters_.sourceDevice) { |
| 1057 CancelCurrentFling(); | 1057 CancelCurrentFling(); |
| 1058 return false; | 1058 return false; |
| 1059 } | 1059 } |
| 1060 | 1060 |
| 1061 switch (gesture_event.type) { | 1061 switch (gesture_event.type()) { |
| 1062 case WebInputEvent::GestureTapCancel: | 1062 case WebInputEvent::GestureTapCancel: |
| 1063 case WebInputEvent::GestureTapDown: | 1063 case WebInputEvent::GestureTapDown: |
| 1064 return false; | 1064 return false; |
| 1065 | 1065 |
| 1066 case WebInputEvent::GestureScrollBegin: | 1066 case WebInputEvent::GestureScrollBegin: |
| 1067 if (!input_handler_->IsCurrentlyScrollingLayerAt( | 1067 if (!input_handler_->IsCurrentlyScrollingLayerAt( |
| 1068 gfx::Point(gesture_event.x, gesture_event.y), | 1068 gfx::Point(gesture_event.x, gesture_event.y), |
| 1069 fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchpad | 1069 fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchpad |
| 1070 ? cc::InputHandler::NON_BUBBLING_GESTURE | 1070 ? cc::InputHandler::NON_BUBBLING_GESTURE |
| 1071 : cc::InputHandler::TOUCHSCREEN)) { | 1071 : cc::InputHandler::TOUCHSCREEN)) { |
| 1072 CancelCurrentFling(); | 1072 CancelCurrentFling(); |
| 1073 return false; | 1073 return false; |
| 1074 } | 1074 } |
| 1075 | 1075 |
| 1076 // TODO(jdduke): Use |gesture_event.data.scrollBegin.delta{X,Y}Hint| to | 1076 // TODO(jdduke): Use |gesture_event.data.scrollBegin.delta{X,Y}Hint| to |
| 1077 // determine if the ScrollBegin should immediately cancel the fling. | 1077 // determine if the ScrollBegin should immediately cancel the fling. |
| 1078 ExtendBoostedFlingTimeout(gesture_event); | 1078 ExtendBoostedFlingTimeout(gesture_event); |
| 1079 return true; | 1079 return true; |
| 1080 | 1080 |
| 1081 case WebInputEvent::GestureScrollUpdate: { | 1081 case WebInputEvent::GestureScrollUpdate: { |
| 1082 const double time_since_last_boost_event = | 1082 const double time_since_last_boost_event = |
| 1083 event.timeStampSeconds - last_fling_boost_event_.timeStampSeconds; | 1083 event.timeStampSeconds() - last_fling_boost_event_.timeStampSeconds(); |
| 1084 const double time_since_last_fling_animate = std::max( | 1084 const double time_since_last_fling_animate = std::max( |
| 1085 0.0, event.timeStampSeconds - InSecondsF(last_fling_animate_time_)); | 1085 0.0, event.timeStampSeconds() - InSecondsF(last_fling_animate_time_)); |
| 1086 if (ShouldSuppressScrollForFlingBoosting(current_fling_velocity_, | 1086 if (ShouldSuppressScrollForFlingBoosting(current_fling_velocity_, |
| 1087 gesture_event, | 1087 gesture_event, |
| 1088 time_since_last_boost_event, | 1088 time_since_last_boost_event, |
| 1089 time_since_last_fling_animate)) { | 1089 time_since_last_fling_animate)) { |
| 1090 ExtendBoostedFlingTimeout(gesture_event); | 1090 ExtendBoostedFlingTimeout(gesture_event); |
| 1091 return true; | 1091 return true; |
| 1092 } | 1092 } |
| 1093 | 1093 |
| 1094 CancelCurrentFling(); | 1094 CancelCurrentFling(); |
| 1095 return false; | 1095 return false; |
| 1096 } | 1096 } |
| 1097 | 1097 |
| 1098 case WebInputEvent::GestureScrollEnd: | 1098 case WebInputEvent::GestureScrollEnd: |
| 1099 // Clear the last fling boost event *prior* to fling cancellation, | 1099 // Clear the last fling boost event *prior* to fling cancellation, |
| 1100 // preventing insertion of a synthetic GestureScrollBegin. | 1100 // preventing insertion of a synthetic GestureScrollBegin. |
| 1101 last_fling_boost_event_ = WebGestureEvent(); | 1101 last_fling_boost_event_ = WebGestureEvent(); |
| 1102 CancelCurrentFling(); | 1102 CancelCurrentFling(); |
| 1103 return true; | 1103 return true; |
| 1104 | 1104 |
| 1105 case WebInputEvent::GestureFlingStart: { | 1105 case WebInputEvent::GestureFlingStart: { |
| 1106 DCHECK_EQ(fling_parameters_.sourceDevice, gesture_event.sourceDevice); | 1106 DCHECK_EQ(fling_parameters_.sourceDevice, gesture_event.sourceDevice); |
| 1107 | 1107 |
| 1108 bool fling_boosted = | 1108 bool fling_boosted = |
| 1109 fling_parameters_.modifiers == gesture_event.modifiers && | 1109 fling_parameters_.modifiers == gesture_event.modifiers() && |
| 1110 ShouldBoostFling(current_fling_velocity_, gesture_event); | 1110 ShouldBoostFling(current_fling_velocity_, gesture_event); |
| 1111 | 1111 |
| 1112 gfx::Vector2dF new_fling_velocity( | 1112 gfx::Vector2dF new_fling_velocity( |
| 1113 gesture_event.data.flingStart.velocityX, | 1113 gesture_event.data.flingStart.velocityX, |
| 1114 gesture_event.data.flingStart.velocityY); | 1114 gesture_event.data.flingStart.velocityY); |
| 1115 DCHECK(!new_fling_velocity.IsZero()); | 1115 DCHECK(!new_fling_velocity.IsZero()); |
| 1116 | 1116 |
| 1117 if (fling_boosted) | 1117 if (fling_boosted) |
| 1118 current_fling_velocity_ += new_fling_velocity; | 1118 current_fling_velocity_ += new_fling_velocity; |
| 1119 else | 1119 else |
| 1120 current_fling_velocity_ = new_fling_velocity; | 1120 current_fling_velocity_ = new_fling_velocity; |
| 1121 | 1121 |
| 1122 WebFloatPoint velocity(current_fling_velocity_.x(), | 1122 WebFloatPoint velocity(current_fling_velocity_.x(), |
| 1123 current_fling_velocity_.y()); | 1123 current_fling_velocity_.y()); |
| 1124 deferred_fling_cancel_time_seconds_ = 0; | 1124 deferred_fling_cancel_time_seconds_ = 0; |
| 1125 disallow_horizontal_fling_scroll_ = !velocity.x; | 1125 disallow_horizontal_fling_scroll_ = !velocity.x; |
| 1126 disallow_vertical_fling_scroll_ = !velocity.y; | 1126 disallow_vertical_fling_scroll_ = !velocity.y; |
| 1127 last_fling_boost_event_ = WebGestureEvent(); | 1127 last_fling_boost_event_ = WebGestureEvent(); |
| 1128 fling_curve_.reset(client_->CreateFlingAnimationCurve( | 1128 fling_curve_.reset(client_->CreateFlingAnimationCurve( |
| 1129 gesture_event.sourceDevice, | 1129 gesture_event.sourceDevice, |
| 1130 velocity, | 1130 velocity, |
| 1131 blink::WebSize())); | 1131 blink::WebSize())); |
| 1132 fling_parameters_.startTime = gesture_event.timeStampSeconds; | 1132 fling_parameters_.startTime = gesture_event.timeStampSeconds(); |
| 1133 fling_parameters_.delta = velocity; | 1133 fling_parameters_.delta = velocity; |
| 1134 fling_parameters_.point = WebPoint(gesture_event.x, gesture_event.y); | 1134 fling_parameters_.point = WebPoint(gesture_event.x, gesture_event.y); |
| 1135 fling_parameters_.globalPoint = | 1135 fling_parameters_.globalPoint = |
| 1136 WebPoint(gesture_event.globalX, gesture_event.globalY); | 1136 WebPoint(gesture_event.globalX, gesture_event.globalY); |
| 1137 | 1137 |
| 1138 TRACE_EVENT_INSTANT2("input", | 1138 TRACE_EVENT_INSTANT2("input", |
| 1139 fling_boosted ? "InputHandlerProxy::FlingBoosted" | 1139 fling_boosted ? "InputHandlerProxy::FlingBoosted" |
| 1140 : "InputHandlerProxy::FlingReplaced", | 1140 : "InputHandlerProxy::FlingReplaced", |
| 1141 TRACE_EVENT_SCOPE_THREAD, | 1141 TRACE_EVENT_SCOPE_THREAD, |
| 1142 "vx", | 1142 "vx", |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1157 return false; | 1157 return false; |
| 1158 } | 1158 } |
| 1159 } | 1159 } |
| 1160 | 1160 |
| 1161 void InputHandlerProxy::ExtendBoostedFlingTimeout( | 1161 void InputHandlerProxy::ExtendBoostedFlingTimeout( |
| 1162 const blink::WebGestureEvent& event) { | 1162 const blink::WebGestureEvent& event) { |
| 1163 TRACE_EVENT_INSTANT0("input", | 1163 TRACE_EVENT_INSTANT0("input", |
| 1164 "InputHandlerProxy::ExtendBoostedFlingTimeout", | 1164 "InputHandlerProxy::ExtendBoostedFlingTimeout", |
| 1165 TRACE_EVENT_SCOPE_THREAD); | 1165 TRACE_EVENT_SCOPE_THREAD); |
| 1166 deferred_fling_cancel_time_seconds_ = | 1166 deferred_fling_cancel_time_seconds_ = |
| 1167 event.timeStampSeconds + kFlingBoostTimeoutDelaySeconds; | 1167 event.timeStampSeconds() + kFlingBoostTimeoutDelaySeconds; |
| 1168 last_fling_boost_event_ = event; | 1168 last_fling_boost_event_ = event; |
| 1169 } | 1169 } |
| 1170 | 1170 |
| 1171 void InputHandlerProxy::Animate(base::TimeTicks time) { | 1171 void InputHandlerProxy::Animate(base::TimeTicks time) { |
| 1172 // If using synchronous animate, then only expect Animate attempts started by | 1172 // If using synchronous animate, then only expect Animate attempts started by |
| 1173 // the synchronous system. Don't let the InputHandler try to Animate also. | 1173 // the synchronous system. Don't let the InputHandler try to Animate also. |
| 1174 DCHECK(!input_handler_->IsCurrentlyScrollingViewport() || | 1174 DCHECK(!input_handler_->IsCurrentlyScrollingViewport() || |
| 1175 allow_root_animate_); | 1175 allow_root_animate_); |
| 1176 | 1176 |
| 1177 if (scroll_elasticity_controller_) | 1177 if (scroll_elasticity_controller_) |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1358 has_fling_animation_started_ = false; | 1358 has_fling_animation_started_ = false; |
| 1359 gesture_scroll_on_impl_thread_ = false; | 1359 gesture_scroll_on_impl_thread_ = false; |
| 1360 current_fling_velocity_ = gfx::Vector2dF(); | 1360 current_fling_velocity_ = gfx::Vector2dF(); |
| 1361 fling_parameters_ = blink::WebActiveWheelFlingParameters(); | 1361 fling_parameters_ = blink::WebActiveWheelFlingParameters(); |
| 1362 | 1362 |
| 1363 if (deferred_fling_cancel_time_seconds_) { | 1363 if (deferred_fling_cancel_time_seconds_) { |
| 1364 deferred_fling_cancel_time_seconds_ = 0; | 1364 deferred_fling_cancel_time_seconds_ = 0; |
| 1365 | 1365 |
| 1366 WebGestureEvent last_fling_boost_event = last_fling_boost_event_; | 1366 WebGestureEvent last_fling_boost_event = last_fling_boost_event_; |
| 1367 last_fling_boost_event_ = WebGestureEvent(); | 1367 last_fling_boost_event_ = WebGestureEvent(); |
| 1368 if (last_fling_boost_event.type == WebInputEvent::GestureScrollBegin || | 1368 if (last_fling_boost_event.type() == WebInputEvent::GestureScrollBegin || |
| 1369 last_fling_boost_event.type == WebInputEvent::GestureScrollUpdate) { | 1369 last_fling_boost_event.type() == WebInputEvent::GestureScrollUpdate) { |
| 1370 // Synthesize a GestureScrollBegin, as the original was suppressed. | 1370 // Synthesize a GestureScrollBegin, as the original was suppressed. |
| 1371 HandleInputEvent(ObtainGestureScrollBegin(last_fling_boost_event)); | 1371 HandleInputEvent(ObtainGestureScrollBegin(last_fling_boost_event)); |
| 1372 } | 1372 } |
| 1373 } | 1373 } |
| 1374 | 1374 |
| 1375 return had_fling_animation; | 1375 return had_fling_animation; |
| 1376 } | 1376 } |
| 1377 | 1377 |
| 1378 void InputHandlerProxy::RequestAnimation() { | 1378 void InputHandlerProxy::RequestAnimation() { |
| 1379 // When a SynchronousInputHandler is present, root flings should go through | 1379 // When a SynchronousInputHandler is present, root flings should go through |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1532 scroll_elasticity_controller_->GetWeakPtr(), gesture_event, | 1532 scroll_elasticity_controller_->GetWeakPtr(), gesture_event, |
| 1533 scroll_result)); | 1533 scroll_result)); |
| 1534 } | 1534 } |
| 1535 | 1535 |
| 1536 void InputHandlerProxy::SetTickClockForTesting( | 1536 void InputHandlerProxy::SetTickClockForTesting( |
| 1537 std::unique_ptr<base::TickClock> tick_clock) { | 1537 std::unique_ptr<base::TickClock> tick_clock) { |
| 1538 tick_clock_ = std::move(tick_clock); | 1538 tick_clock_ = std::move(tick_clock); |
| 1539 } | 1539 } |
| 1540 | 1540 |
| 1541 } // namespace ui | 1541 } // namespace ui |
| OLD | NEW |