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.core import video 6from telemetry.core import web_contents 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, backend_list): 23 super(Tab, self).__init__(inspector_backend, backend_list) 24 25 @property 26 def browser(self): 27 """The browser in which this tab resides.""" 28 return self._inspector_backend.browser 29 30 @property 31 def url(self): 32 return self._inspector_backend.url 33 34 @property 35 def dom_stats(self): 36 """A dictionary populated with measured DOM statistics. 37 38 Currently this dictionary contains: 39 { 40 'document_count': integer, 41 'node_count': integer, 42 'event_listener_count': integer 43 } 44 """ 45 dom_counters = self._inspector_backend.GetDOMStats( 46 timeout=DEFAULT_TAB_TIMEOUT) 47 assert (len(dom_counters) == 3 and 48 all([x in dom_counters for x in ['document_count', 'node_count', 49 'event_listener_count']])) 50 return dom_counters 51 52 def Activate(self): 53 """Brings this tab to the foreground asynchronously. 54 55 Not all browsers or browser versions support this method. 56 Be sure to check browser.supports_tab_control. 57 58 Please note: this is asynchronous. There is a delay between this call 59 and the page's documentVisibilityState becoming 'visible', and yet more 60 delay until the actual tab is visible to the user. None of these delays 61 are included in this call.""" 62 self._backend_list.ActivateTab(self._inspector_backend.debugger_url) 63 64 def Close(self): 65 """Closes this tab. 66 67 Not all browsers or browser versions support this method. 68 Be sure to check browser.supports_tab_control.""" 69 self._backend_list.CloseTab(self._inspector_backend.debugger_url) 70 71 @property 72 def screenshot_supported(self): 73 """True if the browser instance is capable of capturing screenshots.""" 74 return self._inspector_backend.screenshot_supported 75 76 def Screenshot(self, timeout=DEFAULT_TAB_TIMEOUT): 77 """Capture a screenshot of the tab's contents. 78 79 Returns: 80 A telemetry.core.Bitmap. 81 """ 82 return self._inspector_backend.Screenshot(timeout) 83 84 @property 85 def video_capture_supported(self): 86 """True if the browser instance is capable of capturing video.""" 87 return self.browser.platform.CanCaptureVideo() 88 89 def Highlight(self, color): 90 """Synchronously highlights entire tab contents with the given RgbaColor. 91 92 TODO(tonyg): It is possible that the z-index hack here might not work for 93 all pages. If this happens, DevTools also provides a method for this. 94 """ 95 self.ExecuteJavaScript(""" 96 (function() { 97 var screen = document.createElement('div'); 98 screen.style.background = 'rgba(%d, %d, %d, %d)'; 99 screen.style.position = 'fixed'; 100 screen.style.top = '0'; 101 screen.style.left = '0'; 102 screen.style.width = '100%%'; 103 screen.style.height = '100%%'; 104 screen.style.zIndex = '2147483638'; 105 document.body.appendChild(screen); 106 requestAnimationFrame(function() { 107 requestAnimationFrame(function() { 108 window.__telemetry_screen_%d = screen; 109 }); 110 }); 111 })(); 112 """ % (color.r, color.g, color.b, color.a, int(color))) 113 self.WaitForJavaScriptExpression( 114 '!!window.__telemetry_screen_%d' % int(color), 5) 115 116 def ClearHighlight(self, color): 117 """Clears a highlight of the given bitmap.RgbaColor.""" 118 self.ExecuteJavaScript(""" 119 (function() { 120 document.body.removeChild(window.__telemetry_screen_%d); 121 requestAnimationFrame(function() { 122 requestAnimationFrame(function() { 123 window.__telemetry_screen_%d = null; 124 console.time('__ClearHighlight.video_capture_start'); 125 console.timeEnd('__ClearHighlight.video_capture_start'); 126 }); 127 }); 128 })(); 129 """ % (int(color), int(color))) 130 self.WaitForJavaScriptExpression( 131 '!window.__telemetry_screen_%d' % int(color), 5) 132 133 def StartVideoCapture(self, min_bitrate_mbps, 134 highlight_bitmap=video.HIGHLIGHT_ORANGE_FRAME): 135 """Starts capturing video of the tab's contents. 136 137 This works by flashing the entire tab contents to a arbitrary color and then 138 starting video recording. When the frames are processed, we can look for 139 that flash as the content bounds. 140 141 Args: 142 min_bitrate_mbps: The minimum caputre bitrate in MegaBits Per Second. 143 The platform is free to deliver a higher bitrate if it can do so 144 without increasing overhead. 145 """ 146 self.Highlight(highlight_bitmap) 147 self.browser.platform.StartVideoCapture(min_bitrate_mbps) 148 self.ClearHighlight(highlight_bitmap) 149 150 @property 151 def is_video_capture_running(self): 152 return self.browser.platform.is_video_capture_running 153 154 def StopVideoCapture(self): 155 """Stops recording video of the tab's contents. 156 157 This looks for the initial color flash in the first frame to establish the 158 tab content boundaries and then omits all frames displaying the flash. 159 160 Returns: 161 video: A video object which is a telemetry.core.Video 162 """ 163 return self.browser.platform.StopVideoCapture() 164 165 def WaitForNavigate(self, timeout=DEFAULT_TAB_TIMEOUT): 166 """Waits for the navigation to complete. 167 168 The current page is expect to be in a navigation. 169 This function returns when the navigation is complete or when 170 the timeout has been exceeded. 171 """ 172 self._inspector_backend.WaitForNavigate(timeout) 173 174 def Navigate(self, url, script_to_evaluate_on_commit=None, 175 timeout=DEFAULT_TAB_TIMEOUT): 176 """Navigates to url. 177 178 If |script_to_evaluate_on_commit| is given, the script source string will be 179 evaluated when the navigation is committed. This is after the context of 180 the page exists, but before any script on the page itself has executed. 181 """ 182 self._inspector_backend.Navigate(url, script_to_evaluate_on_commit, timeout) 183 184 def GetCookieByName(self, name, timeout=DEFAULT_TAB_TIMEOUT): 185 """Returns the value of the cookie by the given |name|.""" 186 return self._inspector_backend.GetCookieByName(name, timeout) 187 188 def CollectGarbage(self): 189 self._inspector_backend.CollectGarbage() 190 191 def ClearCache(self, force): 192 """Clears the browser's networking related disk, memory and other caches. 193 194 Args: 195 force: Iff true, navigates to about:blank which destroys the previous 196 renderer, ensuring that even "live" resources in the memory cache are 197 cleared. 198 """ 199 self.browser.platform.FlushDnsCache() 200 self.ExecuteJavaScript(""" 201 if (window.chrome && chrome.benchmarking && 202 chrome.benchmarking.clearCache) { 203 chrome.benchmarking.clearCache(); 204 chrome.benchmarking.clearPredictorCache(); 205 chrome.benchmarking.clearHostResolverCache(); 206 } 207 """) 208 if force: 209 self.Navigate('about:blank') 210