• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.browser import web_contents
6from telemetry.internal.image_processing import video
7
8DEFAULT_TAB_TIMEOUT = 60
9
10
11class Tab(web_contents.WebContents):
12  """Represents a tab in the browser
13
14  The important parts of the Tab object are in the runtime and page objects.
15  E.g.:
16      # Navigates the tab to a given url.
17      tab.Navigate('http://www.google.com/')
18
19      # Evaluates 1+1 in the tab's JavaScript context.
20      tab.Evaluate('1+1')
21  """
22  def __init__(self, inspector_backend, tab_list_backend, browser):
23    super(Tab, self).__init__(inspector_backend)
24    self._tab_list_backend = tab_list_backend
25    self._browser = browser
26
27  @property
28  def browser(self):
29    """The browser in which this tab resides."""
30    return self._browser
31
32  @property
33  def url(self):
34    """Returns the URL of the tab, as reported by devtools.
35
36    Raises:
37      devtools_http.DevToolsClientConnectionError
38    """
39    return self._inspector_backend.url
40
41  @property
42  def dom_stats(self):
43    """A dictionary populated with measured DOM statistics.
44
45    Currently this dictionary contains:
46    {
47      'document_count': integer,
48      'node_count': integer,
49      'event_listener_count': integer
50    }
51
52    Raises:
53      inspector_memory.InspectorMemoryException
54      exceptions.TimeoutException
55      exceptions.DevtoolsTargetCrashException
56    """
57    dom_counters = self._inspector_backend.GetDOMStats(
58        timeout=DEFAULT_TAB_TIMEOUT)
59    assert (len(dom_counters) == 3 and
60            all([x in dom_counters for x in ['document_count', 'node_count',
61                                             'event_listener_count']]))
62    return dom_counters
63
64  def Activate(self):
65    """Brings this tab to the foreground asynchronously.
66
67    Not all browsers or browser versions support this method.
68    Be sure to check browser.supports_tab_control.
69
70    Please note: this is asynchronous. There is a delay between this call
71    and the page's documentVisibilityState becoming 'visible', and yet more
72    delay until the actual tab is visible to the user. None of these delays
73    are included in this call.
74
75    Raises:
76      devtools_http.DevToolsClientConnectionError
77      devtools_client_backend.TabNotFoundError
78      tab_list_backend.TabUnexpectedResponseException
79    """
80    self._tab_list_backend.ActivateTab(self.id)
81
82  def Close(self):
83    """Closes this tab.
84
85    Not all browsers or browser versions support this method.
86    Be sure to check browser.supports_tab_control.
87
88    Raises:
89      devtools_http.DevToolsClientConnectionError
90      devtools_client_backend.TabNotFoundError
91      tab_list_backend.TabUnexpectedResponseException
92      exceptions.TimeoutException
93    """
94    self._tab_list_backend.CloseTab(self.id)
95
96  @property
97  def screenshot_supported(self):
98    """True if the browser instance is capable of capturing screenshots."""
99    return self._inspector_backend.screenshot_supported
100
101  def Screenshot(self, timeout=DEFAULT_TAB_TIMEOUT):
102    """Capture a screenshot of the tab's contents.
103
104    Returns:
105      A telemetry.core.Bitmap.
106    Raises:
107      exceptions.WebSocketDisconnected
108      exceptions.TimeoutException
109      exceptions.DevtoolsTargetCrashException
110    """
111    return self._inspector_backend.Screenshot(timeout)
112
113  @property
114  def video_capture_supported(self):
115    """True if the browser instance is capable of capturing video."""
116    return self.browser.platform.CanCaptureVideo()
117
118  def Highlight(self, color):
119    """Synchronously highlights entire tab contents with the given RgbaColor.
120
121    TODO(tonyg): It is possible that the z-index hack here might not work for
122    all pages. If this happens, DevTools also provides a method for this.
123
124    Raises:
125      exceptions.EvaluateException
126      exceptions.WebSocketDisconnected
127      exceptions.TimeoutException
128      exceptions.DevtoolsTargetCrashException
129    """
130    self.ExecuteJavaScript("""
131      (function() {
132        var screen = document.createElement('div');
133        screen.style.background = 'rgba(%d, %d, %d, %d)';
134        screen.style.position = 'fixed';
135        screen.style.top = '0';
136        screen.style.left = '0';
137        screen.style.width = '100%%';
138        screen.style.height = '100%%';
139        screen.style.zIndex = '2147483638';
140        document.body.appendChild(screen);
141        requestAnimationFrame(function() {
142          requestAnimationFrame(function() {
143            window.__telemetry_screen_%d = screen;
144          });
145        });
146      })();
147    """ % (color.r, color.g, color.b, color.a, int(color)))
148    self.WaitForJavaScriptExpression(
149        '!!window.__telemetry_screen_%d' % int(color), 5)
150
151  def ClearHighlight(self, color):
152    """Clears a highlight of the given bitmap.RgbaColor.
153
154    Raises:
155      exceptions.EvaluateException
156      exceptions.WebSocketDisconnected
157      exceptions.TimeoutException
158      exceptions.DevtoolsTargetCrashException
159    """
160    self.ExecuteJavaScript("""
161      (function() {
162        document.body.removeChild(window.__telemetry_screen_%d);
163        requestAnimationFrame(function() {
164          requestAnimationFrame(function() {
165            window.__telemetry_screen_%d = null;
166            console.time('__ClearHighlight.video_capture_start');
167            console.timeEnd('__ClearHighlight.video_capture_start');
168          });
169        });
170      })();
171    """ % (int(color), int(color)))
172    self.WaitForJavaScriptExpression(
173        '!window.__telemetry_screen_%d' % int(color), 5)
174
175  def StartVideoCapture(self, min_bitrate_mbps,
176                        highlight_bitmap=video.HIGHLIGHT_ORANGE_FRAME):
177    """Starts capturing video of the tab's contents.
178
179    This works by flashing the entire tab contents to a arbitrary color and then
180    starting video recording. When the frames are processed, we can look for
181    that flash as the content bounds.
182
183    Args:
184      min_bitrate_mbps: The minimum caputre bitrate in MegaBits Per Second.
185          The platform is free to deliver a higher bitrate if it can do so
186          without increasing overhead.
187
188    Raises:
189      exceptions.EvaluateException
190      exceptions.WebSocketDisconnected
191      exceptions.TimeoutException
192      exceptions.DevtoolsTargetCrashException
193      ValueError: If the required |min_bitrate_mbps| can't be achieved.
194    """
195    self.Highlight(highlight_bitmap)
196    self.browser.platform.StartVideoCapture(min_bitrate_mbps)
197    self.ClearHighlight(highlight_bitmap)
198
199  @property
200  def is_video_capture_running(self):
201    return self.browser.platform.is_video_capture_running
202
203  def StopVideoCapture(self):
204    """Stops recording video of the tab's contents.
205
206    This looks for the initial color flash in the first frame to establish the
207    tab content boundaries and then omits all frames displaying the flash.
208
209    Returns:
210      video: A video object which is a telemetry.core.Video
211    """
212    return self.browser.platform.StopVideoCapture()
213
214  def GetCookieByName(self, name, timeout=DEFAULT_TAB_TIMEOUT):
215    """Returns the value of the cookie by the given |name|.
216
217    Raises:
218      exceptions.WebSocketDisconnected
219      exceptions.TimeoutException
220      exceptions.DevtoolsTargetCrashException
221    """
222    return self._inspector_backend.GetCookieByName(name, timeout)
223
224  def CollectGarbage(self):
225    """Forces a garbage collection.
226
227    Raises:
228      exceptions.WebSocketDisconnected
229      exceptions.TimeoutException
230      exceptions.DevtoolsTargetCrashException
231    """
232    self._inspector_backend.CollectGarbage()
233
234  def ClearCache(self, force):
235    """Clears the browser's networking related disk, memory and other caches.
236
237    Args:
238      force: Iff true, navigates to about:blank which destroys the previous
239          renderer, ensuring that even "live" resources in the memory cache are
240          cleared.
241
242    Raises:
243      exceptions.EvaluateException
244      exceptions.WebSocketDisconnected
245      exceptions.TimeoutException
246      exceptions.DevtoolsTargetCrashException
247      errors.DeviceUnresponsiveError
248    """
249    self.browser.platform.FlushDnsCache()
250    self.ExecuteJavaScript("""
251        if (window.chrome && chrome.benchmarking &&
252            chrome.benchmarking.clearCache) {
253          chrome.benchmarking.clearCache();
254          chrome.benchmarking.clearPredictorCache();
255          chrome.benchmarking.clearHostResolverCache();
256        }
257    """)
258    if force:
259      self.Navigate('about:blank')
260