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
5from telemetry.internal.actions import page_action
6from telemetry.internal.actions import utils
7
8
9class ScrollBounceAction(page_action.PageAction):
10  def __init__(self, selector=None, text=None, element_function=None,
11               left_start_ratio=0.5, top_start_ratio=0.5,
12               direction='down', distance=100,
13               overscroll=10, repeat_count=10,
14               speed_in_pixels_per_second=400,
15               synthetic_gesture_source=page_action.GESTURE_SOURCE_DEFAULT):
16    super(ScrollBounceAction, self).__init__()
17    if direction not in ['down', 'up', 'left', 'right']:
18      raise page_action.PageActionNotSupported(
19          'Invalid scroll direction: %s' % self.direction)
20    self._selector = selector
21    self._text = text
22    self._element_function = element_function
23    self._left_start_ratio = left_start_ratio
24    self._top_start_ratio = top_start_ratio
25    # Should be big enough to do more than just hide the URL bar.
26    self._distance = distance
27    self._direction = direction
28    # This needs to be < height / repeat_count so we don't walk off the screen.
29    # We also probably don't want to spend more than a couple frames in
30    # overscroll since it may mask any synthetic delays.
31    self._overscroll = overscroll
32    # It's the transitions we really want to stress, make this big.
33    self._repeat_count = repeat_count
34    # 7 pixels per frame should be plenty of frames.
35    self._speed = speed_in_pixels_per_second
36    self._synthetic_gesture_source = ('chrome.gpuBenchmarking.%s_INPUT' %
37                                      synthetic_gesture_source)
38
39    if (self._selector is None and self._text is None and
40        self._element_function is None):
41      self._element_function = '(document.scrollingElement || document.body)'
42
43  def WillRunAction(self, tab):
44    utils.InjectJavaScript(tab, 'gesture_common.js')
45    utils.InjectJavaScript(tab, 'scroll_bounce.js')
46
47    # Fail if browser doesn't support synthetic scroll bounce gestures.
48    if not tab.EvaluateJavaScript(
49        'window.__ScrollBounceAction_SupportedByBrowser()'):
50      raise page_action.PageActionNotSupported(
51          'Synthetic scroll bounce not supported for this browser')
52
53    # Fail if we can't send touch events (bouncing is really only
54    # interesting for touch)
55    if not page_action.IsGestureSourceTypeSupported(tab, 'touch'):
56      raise page_action.PageActionNotSupported(
57          'Touch scroll not supported for this browser')
58
59    if (self._synthetic_gesture_source ==
60        'chrome.gpuBenchmarking.MOUSE_INPUT'):
61      raise page_action.PageActionNotSupported(
62          'ScrollBounce page action does not support mouse input')
63
64    done_callback = 'function() { window.__scrollBounceActionDone = true; }'
65    tab.ExecuteJavaScript("""
66        window.__scrollBounceActionDone = false;
67        window.__scrollBounceAction = new __ScrollBounceAction(%s);"""
68        % (done_callback))
69
70  def RunAction(self, tab):
71    code = '''
72        function(element, info) {
73          if (!element) {
74            throw Error('Cannot find element: ' + info);
75          }
76          window.__scrollBounceAction.start({
77            element: element,
78            left_start_ratio: %s,
79            top_start_ratio: %s,
80            direction: '%s',
81            distance: %s,
82            overscroll: %s,
83            repeat_count: %s,
84            speed: %s
85          });
86        }''' % (self._left_start_ratio,
87                self._top_start_ratio,
88                self._direction,
89                self._distance,
90                self._overscroll,
91                self._repeat_count,
92                self._speed)
93    page_action.EvaluateCallbackWithElement(
94        tab, code, selector=self._selector, text=self._text,
95        element_function=self._element_function)
96    tab.WaitForJavaScriptExpression('window.__scrollBounceActionDone', 60)
97