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.
4import os
5
6from telemetry.internal.actions import page_action
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    for js_file in ['gesture_common.js', 'scroll_bounce.js']:
45      with open(os.path.join(os.path.dirname(__file__), js_file)) as f:
46        js = f.read()
47        tab.ExecuteJavaScript(js)
48
49    # Fail if browser doesn't support synthetic scroll bounce gestures.
50    if not tab.EvaluateJavaScript(
51        'window.__ScrollBounceAction_SupportedByBrowser()'):
52      raise page_action.PageActionNotSupported(
53          'Synthetic scroll bounce not supported for this browser')
54
55    # Fail if we can't send touch events (bouncing is really only
56    # interesting for touch)
57    if not page_action.IsGestureSourceTypeSupported(tab, 'touch'):
58      raise page_action.PageActionNotSupported(
59          'Touch scroll not supported for this browser')
60
61    if (self._synthetic_gesture_source ==
62        'chrome.gpuBenchmarking.MOUSE_INPUT'):
63      raise page_action.PageActionNotSupported(
64          'ScrollBounce page action does not support mouse input')
65
66    done_callback = 'function() { window.__scrollBounceActionDone = true; }'
67    tab.ExecuteJavaScript("""
68        window.__scrollBounceActionDone = false;
69        window.__scrollBounceAction = new __ScrollBounceAction(%s);"""
70        % (done_callback))
71
72  def RunAction(self, tab):
73    code = '''
74        function(element, info) {
75          if (!element) {
76            throw Error('Cannot find element: ' + info);
77          }
78          window.__scrollBounceAction.start({
79            element: element,
80            left_start_ratio: %s,
81            top_start_ratio: %s,
82            direction: '%s',
83            distance: %s,
84            overscroll: %s,
85            repeat_count: %s,
86            speed: %s
87          });
88        }''' % (self._left_start_ratio,
89                self._top_start_ratio,
90                self._direction,
91                self._distance,
92                self._overscroll,
93                self._repeat_count,
94                self._speed)
95    page_action.EvaluateCallbackWithElement(
96        tab, code, selector=self._selector, text=self._text,
97        element_function=self._element_function)
98    tab.WaitForJavaScriptExpression('window.__scrollBounceActionDone', 60)
99