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
5import re
6
7from telemetry import decorators
8
9GESTURE_SOURCE_DEFAULT = 'DEFAULT'
10GESTURE_SOURCE_MOUSE = 'MOUSE'
11GESTURE_SOURCE_TOUCH = 'TOUCH'
12SUPPORTED_GESTURE_SOURCES = (GESTURE_SOURCE_DEFAULT,
13                             GESTURE_SOURCE_MOUSE,
14                             GESTURE_SOURCE_TOUCH)
15
16class PageActionNotSupported(Exception):
17  pass
18
19class PageActionFailed(Exception):
20  pass
21
22
23class PageAction(object):
24  """Represents an action that a user might try to perform to a page."""
25
26  def WillRunAction(self, tab):
27    """Override to do action-specific setup before
28    Test.WillRunAction is called."""
29    pass
30
31  def RunAction(self, tab):
32    raise NotImplementedError()
33
34  def CleanUp(self, tab):
35    pass
36
37def EvaluateCallbackWithElement(
38    tab, callback_js, selector=None, text=None, element_function=None,
39    wait=False, timeout_in_seconds=60):
40  """Evaluates the JavaScript callback with the given element.
41
42  The element may be selected via selector, text, or element_function.
43  Only one of these arguments must be specified.
44
45  Returns:
46    The callback's return value, if any. The return value must be
47    convertible to JSON.
48
49  Args:
50    tab: A telemetry.core.Tab object.
51    callback_js: The JavaScript callback to call (as string).
52        The callback receive 2 parameters: the element, and information
53        string about what method was used to retrieve the element.
54        Example: '''
55          function(element, info) {
56            if (!element) {
57              throw Error('Can not find element: ' + info);
58            }
59            element.click()
60          }'''
61    selector: A CSS selector describing the element.
62    text: The element must contains this exact text.
63    element_function: A JavaScript function (as string) that is used
64        to retrieve the element. For example:
65        '(function() { return foo.element; })()'.
66    wait: Whether to wait for the return value to be true.
67    timeout_in_seconds: The timeout for wait (if waiting).
68  """
69  count = 0
70  info_msg = ''
71  if element_function is not None:
72    count = count + 1
73    info_msg = 'using element_function "%s"' % re.escape(element_function)
74  if selector is not None:
75    count = count + 1
76    info_msg = 'using selector "%s"' % _EscapeSelector(selector)
77    element_function = 'document.querySelector(\'%s\')' % _EscapeSelector(
78        selector)
79  if text is not None:
80    count = count + 1
81    info_msg = 'using exact text match "%s"' % re.escape(text)
82    element_function = '''
83        (function() {
84          function _findElement(element, text) {
85            if (element.innerHTML == text) {
86              return element;
87            }
88
89            var childNodes = element.childNodes;
90            for (var i = 0, len = childNodes.length; i < len; ++i) {
91              var found = _findElement(childNodes[i], text);
92              if (found) {
93                return found;
94              }
95            }
96            return null;
97          }
98          return _findElement(document, '%s');
99        })()''' % text
100
101  if count != 1:
102    raise PageActionFailed(
103        'Must specify 1 way to retrieve element, but %s was specified.' % count)
104
105  code = '''
106      (function() {
107        var element = %s;
108        var callback = %s;
109        return callback(element, '%s');
110      })()''' % (element_function, callback_js, info_msg)
111
112  if wait:
113    tab.WaitForJavaScriptExpression(code, timeout_in_seconds)
114    return True
115  else:
116    return tab.EvaluateJavaScript(code)
117
118def _EscapeSelector(selector):
119  return selector.replace('\'', '\\\'')
120
121
122@decorators.Cache
123def IsGestureSourceTypeSupported(tab, gesture_source_type):
124  # TODO(dominikg): remove once support for
125  #                 'chrome.gpuBenchmarking.gestureSourceTypeSupported' has
126  #                 been rolled into reference build.
127  if tab.EvaluateJavaScript("""
128      typeof chrome.gpuBenchmarking.gestureSourceTypeSupported ===
129          'undefined'"""):
130    return (tab.browser.platform.GetOSName() != 'mac' or
131            gesture_source_type.lower() != 'touch')
132
133  return tab.EvaluateJavaScript("""
134      chrome.gpuBenchmarking.gestureSourceTypeSupported(
135          chrome.gpuBenchmarking.%s_INPUT)"""
136      % (gesture_source_type.upper()))
137