1# Copyright 2012 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 7from telemetry.util import js_template 8 9 10class ScrollAction(page_action.PageAction): 11 # TODO(chrishenry): Ignore attributes, to be deleted when usage in 12 # other repo is cleaned up. 13 def __init__(self, selector=None, text=None, element_function=None, 14 left_start_ratio=0.5, top_start_ratio=0.5, direction='down', 15 distance=None, distance_expr=None, 16 speed_in_pixels_per_second=800, use_touch=False, 17 synthetic_gesture_source=page_action.GESTURE_SOURCE_DEFAULT): 18 super(ScrollAction, self).__init__() 19 if direction not in ('down', 'up', 'left', 'right', 20 'downleft', 'downright', 21 'upleft', 'upright'): 22 raise page_action.PageActionNotSupported( 23 'Invalid scroll direction: %s' % self.direction) 24 self._selector = selector 25 self._text = text 26 self._element_function = element_function 27 self._left_start_ratio = left_start_ratio 28 self._top_start_ratio = top_start_ratio 29 self._direction = direction 30 self._speed = speed_in_pixels_per_second 31 self._use_touch = use_touch 32 self._synthetic_gesture_source = ('chrome.gpuBenchmarking.%s_INPUT' % 33 synthetic_gesture_source) 34 35 self._distance_func = js_template.RenderValue(None) 36 if distance: 37 assert not distance_expr 38 distance_expr = str(distance) 39 if distance_expr: 40 self._distance_func = js_template.Render( 41 'function() { return 0 + {{ @expr }}; }', expr=distance_expr) 42 43 def WillRunAction(self, tab): 44 if self._direction in ('downleft', 'downright', 'upleft', 'upright'): 45 # Diagonal scrolling support was added in Chrome branch number 2332. 46 branch_num = ( 47 tab.browser._browser_backend.devtools_client.GetChromeBranchNumber()) 48 if branch_num < 2332: 49 raise ValueError('Diagonal scrolling requires Chrome branch number' 50 ' 2332 or later. Found branch number %d' % 51 branch_num) 52 utils.InjectJavaScript(tab, 'gesture_common.js') 53 utils.InjectJavaScript(tab, 'scroll.js') 54 55 # Fail if browser doesn't support synthetic scroll gestures. 56 if not tab.EvaluateJavaScript( 57 'window.__ScrollAction_SupportedByBrowser()'): 58 raise page_action.PageActionNotSupported( 59 'Synthetic scroll not supported for this browser') 60 61 # Fail if this action requires touch and we can't send touch events. 62 if self._use_touch: 63 if not page_action.IsGestureSourceTypeSupported(tab, 'touch'): 64 raise page_action.PageActionNotSupported( 65 'Touch scroll not supported for this browser') 66 67 if (self._synthetic_gesture_source == 68 'chrome.gpuBenchmarking.MOUSE_INPUT'): 69 raise page_action.PageActionNotSupported( 70 'Scroll requires touch on this page but mouse input was requested') 71 72 tab.ExecuteJavaScript(""" 73 window.__scrollActionDone = false; 74 window.__scrollAction = new __ScrollAction( 75 {{ @callback }}, {{ @distance }});""", 76 callback='function() { window.__scrollActionDone = true; }', 77 distance=self._distance_func) 78 79 def RunAction(self, tab): 80 if (self._selector is None and self._text is None and 81 self._element_function is None): 82 self._element_function = '(document.scrollingElement || document.body)' 83 84 gesture_source_type = self._synthetic_gesture_source 85 if self._use_touch: 86 gesture_source_type = 'chrome.gpuBenchmarking.TOUCH_INPUT' 87 88 code = js_template.Render(''' 89 function(element, info) { 90 if (!element) { 91 throw Error('Cannot find element: ' + info); 92 } 93 window.__scrollAction.start({ 94 element: element, 95 left_start_ratio: {{ left_start_ratio }}, 96 top_start_ratio: {{ top_start_ratio }}, 97 direction: {{ direction }}, 98 speed: {{ speed }}, 99 gesture_source_type: {{ @gesture_source_type }} 100 }); 101 }''', 102 left_start_ratio=self._left_start_ratio, 103 top_start_ratio=self._top_start_ratio, 104 direction=self._direction, 105 speed=self._speed, 106 gesture_source_type=gesture_source_type) 107 page_action.EvaluateCallbackWithElement( 108 tab, code, selector=self._selector, text=self._text, 109 element_function=self._element_function) 110 tab.WaitForJavaScriptCondition('window.__scrollActionDone', timeout=60) 111